Totally rewritten registry handling.
[platform/upstream/gstreamer.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  *
5  * gstclock.c: Clock subsystem for maintaining time sync
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include <sys/time.h>
24
25 /* #define GST_DEBUG_ENABLED */
26 #include "gst_private.h"
27
28 #include "gstclock.h"
29
30 #define CLASS(clock)  GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock))
31
32 static GMemChunk *_gst_clock_entries_chunk;
33 static GMutex *_gst_clock_entries_chunk_lock;
34 static GList *_gst_clock_entries_pool;
35
36 static void             gst_clock_class_init            (GstClockClass *klass);
37 static void             gst_clock_init                  (GstClock *clock);
38
39
40 static GstObjectClass *parent_class = NULL;
41 /* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */
42
43 typedef struct _GstClockEntry GstClockEntry;
44
45 static void             gst_clock_free_entry            (GstClock *clock, GstClockEntry *entry);
46
47 typedef enum {
48   GST_ENTRY_OK,
49   GST_ENTRY_RESTART,
50 } GstEntryStatus;
51
52 struct _GstClockEntry {
53   GstClockTime           time;
54   GstEntryStatus         status;
55   GstClockCallback       func;
56   gpointer               user_data;
57   GMutex                *lock;
58   GCond                 *cond;
59 };
60
61 #define GST_CLOCK_ENTRY(entry)          ((GstClockEntry *)(entry))
62 #define GST_CLOCK_ENTRY_TIME(entry)     (((GstClockEntry *)(entry))->time)
63 #define GST_CLOCK_ENTRY_LOCK(entry)     (g_mutex_lock ((entry)->lock))
64 #define GST_CLOCK_ENTRY_UNLOCK(entry)   (g_mutex_unlock ((entry)->lock))
65 #define GST_CLOCK_ENTRY_SIGNAL(entry)   (g_cond_signal ((entry)->cond))
66 #define GST_CLOCK_ENTRY_WAIT(entry)     (g_cond_wait (entry->cond, entry->lock))
67 #define GST_CLOCK_ENTRY_TIMED_WAIT(entry, time)         (g_cond_timed_wait (entry->cond, entry->lock, (time)))
68
69 static GstClockEntry*
70 gst_clock_entry_new (GstClockTime time,
71                      GstClockCallback func, gpointer user_data)
72 {
73   GstClockEntry *entry;
74
75   g_mutex_lock (_gst_clock_entries_chunk_lock);
76   if (_gst_clock_entries_pool) {
77     entry = GST_CLOCK_ENTRY (_gst_clock_entries_pool->data);
78
79     _gst_clock_entries_pool = g_list_remove (_gst_clock_entries_pool, entry);
80     g_mutex_unlock (_gst_clock_entries_chunk_lock);
81   }
82   else {
83     entry = g_mem_chunk_alloc (_gst_clock_entries_chunk);
84     g_mutex_unlock (_gst_clock_entries_chunk_lock);
85
86     entry->lock = g_mutex_new ();
87     entry->cond = g_cond_new ();
88   }
89   entry->time = time;
90   entry->func = func;
91   entry->user_data = user_data;
92
93   return entry;
94 }
95
96 static gint
97 clock_compare_func (gconstpointer a,
98                     gconstpointer b)
99 {
100   GstClockEntry *entry1 = (GstClockEntry *)a;
101   GstClockEntry *entry2 = (GstClockEntry *)b;
102
103   return (entry1->time - entry2->time);
104 }
105
106 GType
107 gst_clock_get_type (void)
108 {
109   static GType clock_type = 0;
110
111   if (!clock_type) {
112     static const GTypeInfo clock_info = {
113       sizeof (GstClockClass),
114       NULL,
115       NULL,
116       (GClassInitFunc) gst_clock_class_init,
117       NULL,
118       NULL,
119       sizeof (GstClock),
120       4,
121       (GInstanceInitFunc) gst_clock_init,
122       NULL
123     };
124     clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock", 
125                                          &clock_info,  G_TYPE_FLAG_ABSTRACT);
126   }
127   return clock_type;
128 }
129
130 static void
131 gst_clock_class_init (GstClockClass *klass)
132 {
133   GObjectClass *gobject_class;
134   GstObjectClass *gstobject_class;
135
136   gobject_class = (GObjectClass*) klass;
137   gstobject_class = (GstObjectClass*) klass;
138
139   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
140
141   if (!g_thread_supported ())
142     g_thread_init (NULL);
143
144   _gst_clock_entries_chunk = g_mem_chunk_new ("GstClockEntries",
145                      sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
146                      G_ALLOC_AND_FREE);
147   _gst_clock_entries_chunk_lock = g_mutex_new ();
148   _gst_clock_entries_pool = NULL;
149 }
150
151 static void
152 gst_clock_init (GstClock *clock)
153 {
154   clock->speed = 1.0;
155   clock->active = FALSE;
156   clock->start_time = 0;
157   clock->last_time = 0;
158   clock->entries = NULL;
159   clock->async_supported = FALSE;
160
161   clock->active_mutex = g_mutex_new ();
162   clock->active_cond = g_cond_new ();
163 }
164
165 /**
166  * gst_clock_async_supported
167  * @clock: a #GstClock to query
168  *
169  * Checks if this clock can support asynchronous notification.
170  *
171  * Returns: TRUE if async notification is supported.
172  */
173 gboolean
174 gst_clock_async_supported (GstClock *clock)
175 {
176   g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
177
178   return clock->async_supported;
179 }
180
181 /**
182  * gst_clock_set_speed
183  * @clock: a #GstClock to modify
184  * @speed: the speed to set on the clock
185  *
186  * Sets the speed on the given clock. 1.0 is the default 
187  * speed.
188  */
189 void
190 gst_clock_set_speed (GstClock *clock, gdouble speed)
191 {
192   g_return_if_fail (GST_IS_CLOCK (clock));
193
194   clock->speed = speed;
195 }
196
197 /**
198  * gst_clock_get_speed
199  * @clock: a #GstClock to query
200  *
201  * Gets the speed of the given clock.
202  *
203  * Returns: the speed of the clock.
204  */
205 gdouble
206 gst_clock_get_speed (GstClock *clock)
207 {
208   g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);
209
210   return clock->speed;
211 }
212
213
214 /**
215  * gst_clock_reset
216  * @clock: a #GstClock to reset
217  *
218  * Reset the clock to time 0.
219  */
220 void
221 gst_clock_reset (GstClock *clock)
222 {
223   GstClockTime time = 0LL;
224
225   g_return_if_fail (GST_IS_CLOCK (clock));
226
227   if (CLASS (clock)->get_internal_time) {
228     time = CLASS (clock)->get_internal_time (clock);
229   }
230
231   GST_LOCK (clock);
232   clock->active = FALSE;
233   clock->start_time = time;
234   clock->last_time = 0LL;
235   GST_UNLOCK (clock);
236 }
237
238 /**
239  * gst_clock_set_active
240  * @clock: a #GstClock to set state of
241  * @active: flag indicating if the clock should be activated (TRUE) or deactivated
242  *
243  * Activates or deactivates the clock based on the active parameter.
244  * As soon as the clock is activated, the time will start ticking.
245  */
246 void
247 gst_clock_set_active (GstClock *clock, gboolean active)
248 {
249   GstClockTime time = 0LL;
250
251   g_return_if_fail (GST_IS_CLOCK (clock));
252
253   clock->active = active;
254                 
255   if (CLASS (clock)->get_internal_time) {
256     time = CLASS (clock)->get_internal_time (clock);
257   }
258
259   GST_LOCK (clock);
260   if (active) {
261     clock->start_time = time - clock->last_time;;
262   }
263   else {
264     clock->last_time = time - clock->start_time;
265   }
266   GST_UNLOCK (clock);
267
268   g_mutex_lock (clock->active_mutex);   
269   g_cond_broadcast (clock->active_cond);        
270   g_mutex_unlock (clock->active_mutex); 
271 }
272
273 /**
274  * gst_clock_is_active
275  * @clock: a #GstClock to query
276  *
277  * Checks if the given clock is active.
278  * 
279  * Returns: TRUE if the clock is active.
280  */
281 gboolean
282 gst_clock_is_active (GstClock *clock)
283 {
284   g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
285
286   return clock->active;
287 }
288
289 /**
290  * gst_clock_get_time
291  * @clock: a #GstClock to query
292  *
293  * Gets the current time of the given clock. The time is always
294  * monotonically increasing.
295  * 
296  * Returns: the time of the clock.
297  */
298 GstClockTime
299 gst_clock_get_time (GstClock *clock)
300 {
301   GstClockTime ret = 0LL;
302
303   g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
304
305   if (!clock->active) {
306     /* clock is not activen return previous time */
307     ret = clock->last_time;
308   }
309   else {
310     if (CLASS (clock)->get_internal_time) {
311       ret = CLASS (clock)->get_internal_time (clock) - clock->start_time;
312     }
313     /* make sure the time is increasing, else return last_time */
314     if (ret < clock->last_time) {
315       ret = clock->last_time;
316     }
317     else {
318       clock->last_time = ret;
319     }
320   }
321
322   return ret;
323 }
324
325 static GstClockID
326 gst_clock_wait_async_func (GstClock *clock, GstClockTime time,
327                            GstClockCallback func, gpointer user_data)
328 {
329   GstClockEntry *entry = NULL;
330   g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
331
332   if (!clock->active) {
333     GST_DEBUG (GST_CAT_CLOCK, "blocking on clock\n");
334     g_mutex_lock (clock->active_mutex); 
335     g_cond_wait (clock->active_cond, clock->active_mutex);      
336     g_mutex_unlock (clock->active_mutex);       
337   }
338
339   entry = gst_clock_entry_new (time, func, user_data);
340
341   GST_LOCK (clock);
342   clock->entries = g_list_insert_sorted (clock->entries, entry, clock_compare_func);
343   GST_UNLOCK (clock);
344
345   return entry;
346 }
347
348 /**
349  * gst_clock_wait
350  * @clock: a #GstClock to wait on
351  * @time: The #GstClockTime to wait for
352  *
353  * Wait and block till the clock reaches the specified time.
354  *
355  * Returns: the #GstClockReturn result of the operation.
356  */
357 GstClockReturn
358 gst_clock_wait (GstClock *clock, GstClockTime time)
359 {
360   GstClockID id;
361   GstClockReturn res;
362   
363   g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED);
364
365   id = gst_clock_wait_async_func (clock, time, NULL, NULL);
366   res = gst_clock_wait_id (clock, id);
367
368   return res;
369 }
370
371 /**
372  * gst_clock_wait_async
373  * @clock: a #GstClock to wait on
374  * @time: The #GstClockTime to wait for
375  * @func: The callback function 
376  * @user_data: User data passed in the calback
377  *
378  * Register a callback on the given clock that will be triggered 
379  * when the clock has reached the given time. A ClockID is returned
380  * that can be used to cancel the request.
381  *
382  * Returns: the clock id or NULL when async notification is not supported.
383  */
384 GstClockID
385 gst_clock_wait_async (GstClock *clock, GstClockTime time,
386                       GstClockCallback func, gpointer user_data)
387 {
388   g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
389
390   if (clock->async_supported) {
391     return gst_clock_wait_async_func (clock, time, func, user_data);
392   }
393   return NULL;
394 }
395
396 /**
397  * gst_clock_cancel_wait_async
398  * @clock: The clock to cancel the request on
399  * @id: The id to cancel
400  *
401  * Cancel an outstanding async notification request with the given ID.
402  */
403 void
404 gst_clock_cancel_wait_async (GstClock *clock, GstClockID id)
405 {
406   g_warning ("not supported");
407 }
408
409 /**
410  * gst_clock_notify_async
411  * @clock: The clock to wait on
412  * @interval: The interval between notifications
413  * @func: The callback function 
414  * @user_data: User data passed in the calback
415  *
416  * Register a callback on the given clock that will be periodically
417  * triggered with the specified interval. A ClockID is returned
418  * that can be used to cancel the request.
419  *
420  * Returns: the clock id or NULL when async notification is not supported.
421  */
422 GstClockID
423 gst_clock_notify_async (GstClock *clock, GstClockTime interval,
424                         GstClockCallback func, gpointer user_data) 
425 {
426   g_warning ("not supported");
427   return NULL;
428 }
429
430 /**
431  * gst_clock_remove_notify_async
432  * @clock: The clock to cancel the request on
433  * @id: The id to cancel
434  *
435  * Cancel an outstanding async notification request with the given ID.
436  */
437 void
438 gst_clock_remove_notify_async (GstClock *clock, GstClockID id)
439 {
440   g_warning ("not supported");
441 }
442
443 static void
444 gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data)
445 {
446   GstClockEntry *entry = (GstClockEntry *) id;
447
448   GST_CLOCK_ENTRY_LOCK (entry);
449   GST_CLOCK_ENTRY_SIGNAL (entry);
450   GST_CLOCK_ENTRY_UNLOCK (entry);
451 }
452
453 /**
454  * gst_clock_wait_id
455  * @clock: The clock to wait on
456  * @id: The clock id to wait on
457  *
458  * Wait and block on the clockid obtained with gst_clock_wait_async.
459  *
460  * Returns: result of the operation.
461  */
462 GstClockReturn
463 gst_clock_wait_id (GstClock *clock, GstClockID id)
464 {
465   GstClockReturn res = GST_CLOCK_TIMEOUT;
466   GstClockEntry *entry = (GstClockEntry *) id;
467   GstClockTime current_real, current, target;
468   GTimeVal timeval;
469   
470   g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR);
471   g_return_val_if_fail (entry, GST_CLOCK_ERROR);
472
473   current = gst_clock_get_time (clock);
474
475   g_get_current_time (&timeval);
476   current_real = GST_TIMEVAL_TO_TIME (timeval);
477
478   GST_CLOCK_ENTRY_LOCK (entry);
479   entry->func = gst_clock_unlock_func;
480   target = GST_CLOCK_ENTRY_TIME (entry) - current + current_real;
481
482   GST_DEBUG (GST_CAT_CLOCK, "%llu %llu %llu\n", target, current, current_real); 
483   
484   if (target > current_real) {
485     timeval.tv_usec = target % 1000000;
486     timeval.tv_sec = target / 1000000;
487
488     GST_CLOCK_ENTRY_TIMED_WAIT (entry, &timeval);
489   }
490   GST_CLOCK_ENTRY_UNLOCK (entry);
491
492   gst_clock_free_entry (clock, entry);
493
494   return res;
495 }
496
497 /**
498  * gst_clock_get_next_id
499  * @clock: The clock to query
500  *
501  * Get the clockid of the next event.
502  *
503  * Returns: a clockid or NULL is no event is pending.
504  */
505 GstClockID
506 gst_clock_get_next_id (GstClock *clock)
507 {
508   GstClockEntry *entry = NULL;
509
510   GST_LOCK (clock);
511   if (clock->entries)
512     entry = GST_CLOCK_ENTRY (clock->entries->data);
513   GST_UNLOCK (clock);
514
515   return (GstClockID *) entry;
516 }
517
518 /**
519  * gst_clock_id_get_time
520  * @id: The clockid to query
521  *
522  * Get the time of the clock ID
523  *
524  * Returns: the time of the given clock id
525  */
526 GstClockTime
527 gst_clock_id_get_time (GstClockID id)
528 {
529   return GST_CLOCK_ENTRY_TIME (id);
530 }
531
532 static void
533 gst_clock_free_entry (GstClock *clock, GstClockEntry *entry)
534 {
535   GST_LOCK (clock);
536   clock->entries = g_list_remove (clock->entries, entry);
537   GST_UNLOCK (clock);
538
539   g_mutex_lock (_gst_clock_entries_chunk_lock);
540   _gst_clock_entries_pool = g_list_prepend (_gst_clock_entries_pool, entry);
541   g_mutex_unlock (_gst_clock_entries_chunk_lock);
542 }
543
544 /**
545  * gst_clock_unlock_id
546  * @clock: The clock that own the id
547  * @id: The clockid to unlock
548  *
549  * Unlock the ClockID.
550  */
551 void
552 gst_clock_unlock_id (GstClock *clock, GstClockID id)
553 {
554   GstClockEntry *entry = (GstClockEntry *) id;
555
556   if (entry->func)
557     entry->func (clock, gst_clock_get_time (clock), id, entry->user_data);
558
559   gst_clock_free_entry (clock, entry);
560 }
561
562 /**
563  * gst_clock_set_resolution
564  * @clock: The clock set the resolution on
565  * @resolution: The resolution to set
566  *
567  * Set the accuracy of the clock.
568  */
569 void
570 gst_clock_set_resolution (GstClock *clock, guint64 resolution)
571 {
572   g_return_if_fail (GST_IS_CLOCK (clock));
573
574   if (CLASS (clock)->set_resolution)
575     CLASS (clock)->set_resolution (clock, resolution);
576 }
577
578 /**
579  * gst_clock_get_resolution
580  * @clock: The clock get the resolution of
581  *
582  * Get the accuracy of the clock.
583  *
584  * Returns: the resolution of the clock in microseconds.
585  */
586 guint64
587 gst_clock_get_resolution (GstClock *clock)
588 {
589   g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
590
591   if (CLASS (clock)->get_resolution)
592     return CLASS (clock)->get_resolution (clock);
593
594   return 1LL;
595 }
596