moap ignore
[platform/upstream/gstreamer.git] / gst / gstsystemclock.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2004 Wim Taymans <wim@fluendo.com>
4  *
5  * gstsystemclock.c: Default clock, uses the system clock
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 /**
24  * SECTION:gstsystemclock
25  * @short_description: Default clock that uses the current system time
26  * @see_also: #GstClock
27  *
28  * The GStreamer core provides a GstSystemClock based on the system time.
29  * Asynchronous callbacks are scheduled from an internal thread.
30  *
31  * Clock implementors are encouraged to subclass this systemclock as it
32  * implements the async notification.
33  *
34  * Subclasses can however override all of the important methods for sync and
35  * async notifications to implement their own callback methods or blocking
36  * wait operations.
37  *
38  * Last reviewed on 2006-03-08 (0.10.4)
39  */
40
41 #include "gst_private.h"
42 #include "gstinfo.h"
43
44 #include "gstsystemclock.h"
45
46 /* Define this to get some extra debug about jitter from each clock_wait */
47 #undef WAIT_DEBUGGING
48
49 /* the one instance of the systemclock */
50 static GstClock *_the_system_clock = NULL;
51
52 static void gst_system_clock_class_init (GstSystemClockClass * klass);
53 static void gst_system_clock_init (GstSystemClock * clock);
54 static void gst_system_clock_dispose (GObject * object);
55
56 static GstClockTime gst_system_clock_get_internal_time (GstClock * clock);
57 static guint64 gst_system_clock_get_resolution (GstClock * clock);
58 static GstClockReturn gst_system_clock_id_wait (GstClock * clock,
59     GstClockEntry * entry);
60 static GstClockReturn gst_system_clock_id_wait_unlocked
61     (GstClock * clock, GstClockEntry * entry);
62 static GstClockReturn gst_system_clock_id_wait_async (GstClock * clock,
63     GstClockEntry * entry);
64 static void gst_system_clock_id_unschedule (GstClock * clock,
65     GstClockEntry * entry);
66 static void gst_system_clock_async_thread (GstClock * clock);
67
68 static GStaticMutex _gst_sysclock_mutex = G_STATIC_MUTEX_INIT;
69
70 static GstClockClass *parent_class = NULL;
71
72 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
73
74 GType
75 gst_system_clock_get_type (void)
76 {
77   static GType clock_type = 0;
78
79   if (G_UNLIKELY (clock_type == 0)) {
80     static const GTypeInfo clock_info = {
81       sizeof (GstSystemClockClass),
82       NULL,
83       NULL,
84       (GClassInitFunc) gst_system_clock_class_init,
85       NULL,
86       NULL,
87       sizeof (GstSystemClock),
88       0,
89       (GInstanceInitFunc) gst_system_clock_init,
90       NULL
91     };
92
93     clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstSystemClock",
94         &clock_info, 0);
95   }
96   return clock_type;
97 }
98
99 static void
100 gst_system_clock_class_init (GstSystemClockClass * klass)
101 {
102   GObjectClass *gobject_class;
103   GstObjectClass *gstobject_class;
104   GstClockClass *gstclock_class;
105
106   gobject_class = (GObjectClass *) klass;
107   gstobject_class = (GstObjectClass *) klass;
108   gstclock_class = (GstClockClass *) klass;
109
110   parent_class = g_type_class_peek_parent (klass);
111
112   gobject_class->dispose = gst_system_clock_dispose;
113
114   gstclock_class->get_internal_time = gst_system_clock_get_internal_time;
115   gstclock_class->get_resolution = gst_system_clock_get_resolution;
116   gstclock_class->wait = gst_system_clock_id_wait;
117   gstclock_class->wait_async = gst_system_clock_id_wait_async;
118   gstclock_class->unschedule = gst_system_clock_id_unschedule;
119 }
120
121 static void
122 gst_system_clock_init (GstSystemClock * clock)
123 {
124   GError *error = NULL;
125
126   GST_OBJECT_FLAG_SET (clock,
127       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
128       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
129       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
130       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
131
132   GST_OBJECT_LOCK (clock);
133   clock->thread = g_thread_create ((GThreadFunc) gst_system_clock_async_thread,
134       clock, TRUE, &error);
135   if (error)
136     goto no_thread;
137
138   /* wait for it to spin up */
139   GST_CLOCK_WAIT (clock);
140   GST_OBJECT_UNLOCK (clock);
141   return;
142
143   /* ERRORS */
144 no_thread:
145   {
146     g_warning ("could not create async clock thread: %s", error->message);
147     GST_OBJECT_UNLOCK (clock);
148   }
149 }
150
151 static void
152 gst_system_clock_dispose (GObject * object)
153 {
154   GstClock *clock = (GstClock *) object;
155
156   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
157   GList *entries;
158
159   /* else we have to stop the thread */
160   GST_OBJECT_LOCK (clock);
161   sysclock->stopping = TRUE;
162   /* unschedule all entries */
163   for (entries = clock->entries; entries; entries = g_list_next (entries)) {
164     GstClockEntry *entry = (GstClockEntry *) entries->data;
165
166     GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
167     entry->status = GST_CLOCK_UNSCHEDULED;
168   }
169   g_list_free (clock->entries);
170   clock->entries = NULL;
171   GST_CLOCK_BROADCAST (clock);
172   GST_OBJECT_UNLOCK (clock);
173
174   if (sysclock->thread)
175     g_thread_join (sysclock->thread);
176   sysclock->thread = NULL;
177   GST_CAT_DEBUG (GST_CAT_CLOCK, "joined thread");
178
179   G_OBJECT_CLASS (parent_class)->dispose (object);
180
181   if (_the_system_clock == clock) {
182     _the_system_clock = NULL;
183     GST_CAT_DEBUG (GST_CAT_CLOCK, "disposed system clock");
184   }
185 }
186
187 /**
188  * gst_system_clock_obtain:
189  *
190  * Get a handle to the default system clock. The refcount of the
191  * clock will be increased so you need to unref the clock after
192  * usage.
193  *
194  * Returns: the default clock.
195  *
196  * MT safe.
197  */
198 GstClock *
199 gst_system_clock_obtain (void)
200 {
201   GstClock *clock;
202
203   g_static_mutex_lock (&_gst_sysclock_mutex);
204   clock = _the_system_clock;
205
206   if (clock == NULL) {
207     GST_CAT_DEBUG (GST_CAT_CLOCK, "creating new static system clock");
208     clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
209         "name", "GstSystemClock", NULL);
210
211     /* we created the global clock; take ownership so
212      * we can hand out instances later */
213     gst_object_ref (clock);
214     gst_object_sink (GST_OBJECT (clock));
215
216     _the_system_clock = clock;
217     g_static_mutex_unlock (&_gst_sysclock_mutex);
218   } else {
219     g_static_mutex_unlock (&_gst_sysclock_mutex);
220     GST_CAT_DEBUG (GST_CAT_CLOCK, "returning static system clock");
221   }
222
223   /* we ref it since we are a clock factory. */
224   gst_object_ref (clock);
225   return clock;
226 }
227
228 /* this thread reads the sorted clock entries from the queue.
229  *
230  * It waits on each of them and fires the callback when the timeout occurs.
231  *
232  * When an entry in the queue was canceled, it is simply skipped.
233  *
234  * When waiting for an entry, it can become canceled, in that case we don't
235  * call the callback but move to the next item in the queue.
236  *
237  * MT safe.
238  */
239 static void
240 gst_system_clock_async_thread (GstClock * clock)
241 {
242   GstSystemClock *sysclock = GST_SYSTEM_CLOCK (clock);
243
244   GST_CAT_DEBUG (GST_CAT_CLOCK, "enter system clock thread");
245   GST_OBJECT_LOCK (clock);
246   /* signal spinup */
247   GST_CLOCK_BROADCAST (clock);
248   /* now enter our (almost) infinite loop */
249   while (!sysclock->stopping) {
250     GstClockEntry *entry;
251     GstClockReturn res;
252
253     /* check if something to be done */
254     while (clock->entries == NULL) {
255       GST_CAT_DEBUG (GST_CAT_CLOCK, "no clock entries, waiting..");
256       /* wait for work to do */
257       GST_CLOCK_WAIT (clock);
258       GST_CAT_DEBUG (GST_CAT_CLOCK, "got signal");
259       /* clock was stopping, exit */
260       if (sysclock->stopping)
261         goto exit;
262     }
263
264     /* pick the next entry */
265     entry = clock->entries->data;
266     /* if it was unscheduled, just move on to the next entry */
267     if (entry->status == GST_CLOCK_UNSCHEDULED) {
268       GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p was unscheduled", entry);
269       goto next_entry;
270     }
271
272     /* now wait for the entry, we already hold the lock */
273     res = gst_system_clock_id_wait_unlocked (clock, (GstClockID) entry);
274
275     switch (res) {
276       case GST_CLOCK_UNSCHEDULED:
277         /* entry was unscheduled, move to the next */
278         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unscheduled", entry);
279         goto next_entry;
280       case GST_CLOCK_OK:
281       case GST_CLOCK_EARLY:
282       {
283         /* entry timed out normally, fire the callback and move to the next
284          * entry */
285         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p unlocked", entry);
286         if (entry->func) {
287           /* unlock before firing the callback */
288           GST_OBJECT_UNLOCK (clock);
289           entry->func (clock, entry->time, (GstClockID) entry,
290               entry->user_data);
291           GST_OBJECT_LOCK (clock);
292         }
293         if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
294           /* adjust time now */
295           entry->time += entry->interval;
296           /* and resort the list now */
297           clock->entries =
298               g_list_sort (clock->entries, gst_clock_id_compare_func);
299           /* and restart */
300           continue;
301         } else {
302           goto next_entry;
303         }
304       }
305       case GST_CLOCK_BUSY:
306         /* somebody unlocked the entry but is was not canceled, This means that
307          * either a new entry was added in front of the queue or some other entry
308          * was canceled. Whatever it is, pick the head entry of the list and
309          * continue waiting. */
310         GST_CAT_DEBUG (GST_CAT_CLOCK, "async entry %p needs restart", entry);
311         continue;
312       default:
313         GST_CAT_DEBUG (GST_CAT_CLOCK,
314             "strange result %d waiting for %p, skipping", res, entry);
315         g_warning ("%s: strange result %d waiting for %p, skipping",
316             GST_OBJECT_NAME (clock), res, entry);
317         goto next_entry;
318     }
319   next_entry:
320     /* we remove the current entry and unref it */
321     clock->entries = g_list_remove (clock->entries, entry);
322     gst_clock_id_unref ((GstClockID) entry);
323   }
324 exit:
325   /* signal exit */
326   GST_CLOCK_BROADCAST (clock);
327   GST_OBJECT_UNLOCK (clock);
328   GST_CAT_DEBUG (GST_CAT_CLOCK, "exit system clock thread");
329 }
330
331 /* MT safe */
332 static GstClockTime
333 gst_system_clock_get_internal_time (GstClock * clock)
334 {
335   GTimeVal timeval;
336
337   g_get_current_time (&timeval);
338
339   return GST_TIMEVAL_TO_TIME (timeval);
340 }
341
342 static guint64
343 gst_system_clock_get_resolution (GstClock * clock)
344 {
345   return 1 * GST_USECOND;
346 }
347
348 /* synchronously wait on the given GstClockEntry.
349  *
350  * We do this by blocking on the global clock GCond variable with
351  * the requested time as a timeout. This allows us to unblock the
352  * entry by signaling the GCond variable.
353  *
354  * Note that signaling the global GCond unlocks all waiting entries. So
355  * we need to check if an unlocked entry has changed when it unlocks.
356  *
357  * Entries that arrive too late are simply not waited on and a
358  * GST_CLOCK_EARLY result is returned.
359  *
360  * should be called with LOCK held.
361  *
362  * MT safe.
363  */
364 static GstClockReturn
365 gst_system_clock_id_wait_unlocked (GstClock * clock, GstClockEntry * entry)
366 {
367   GstClockTime entryt, real, now, target;
368   GstClockTimeDiff diff;
369
370   /* need to call the overridden method */
371   real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
372   entryt = GST_CLOCK_ENTRY_TIME (entry);
373
374   now = gst_clock_adjust_unlocked (clock, real);
375   diff = entryt - now;
376   target = gst_system_clock_get_internal_time (clock) + diff;
377
378   GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p"
379       " target %" GST_TIME_FORMAT
380       " entry %" GST_TIME_FORMAT
381       " now %" GST_TIME_FORMAT
382       " real %" GST_TIME_FORMAT
383       " diff %" G_GINT64_FORMAT,
384       entry,
385       GST_TIME_ARGS (target),
386       GST_TIME_ARGS (entryt), GST_TIME_ARGS (now), GST_TIME_ARGS (real), diff);
387
388   if (diff > 0) {
389     GTimeVal tv;
390
391 #ifdef WAIT_DEBUGGING
392     GstClockTime result, final;
393 #endif
394
395     GST_TIME_TO_TIMEVAL (target, tv);
396
397     while (TRUE) {
398       /* now wait on the entry, it either times out or the cond is signaled. */
399       if (!GST_CLOCK_TIMED_WAIT (clock, &tv)) {
400         /* timeout, this is fine, we can report success now */
401         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked after timeout", entry);
402         entry->status = GST_CLOCK_OK;
403
404 #ifdef WAIT_DEBUGGING
405         real = GST_CLOCK_GET_CLASS (clock)->get_internal_time (clock);
406         result = gst_clock_adjust_unlocked (clock, real);
407         final = gst_system_clock_get_internal_time (clock);
408         GST_CAT_DEBUG (GST_CAT_CLOCK, "Waited for %" G_GINT64_FORMAT
409             " got %" G_GINT64_FORMAT " diff %" G_GINT64_FORMAT
410             " %g target-offset %" G_GINT64_FORMAT " %g", entryt, result,
411             result - entryt,
412             (double) (GstClockTimeDiff) (result - entryt) / GST_SECOND,
413             (final - target),
414             ((double) (GstClockTimeDiff) (final - target)) / GST_SECOND);
415 #endif
416
417         break;
418       } else {
419         /* the waiting is interrupted because the GCond was signaled. This can
420          * be because this or some other entry was unscheduled. */
421         GST_CAT_DEBUG (GST_CAT_CLOCK, "entry %p unlocked with signal", entry);
422         /* if the entry is unscheduled, we can stop waiting for it */
423         if (entry->status == GST_CLOCK_UNSCHEDULED)
424           break;
425       }
426     }
427   } else if (diff == 0) {
428     entry->status = GST_CLOCK_OK;
429   } else {
430     entry->status = GST_CLOCK_EARLY;
431   }
432   return entry->status;
433 }
434
435 static GstClockReturn
436 gst_system_clock_id_wait (GstClock * clock, GstClockEntry * entry)
437 {
438   GstClockReturn ret;
439
440   GST_OBJECT_LOCK (clock);
441   ret = gst_system_clock_id_wait_unlocked (clock, entry);
442   GST_OBJECT_UNLOCK (clock);
443
444   return ret;
445 }
446
447 /* Add an entry to the list of pending async waits. The entry is inserted
448  * in sorted order. If we inserted the entry at the head of the list, we
449  * need to signal the thread as it might either be waiting on it or waiting
450  * for a new entry.
451  *
452  * MT safe.
453  */
454 static GstClockReturn
455 gst_system_clock_id_wait_async (GstClock * clock, GstClockEntry * entry)
456 {
457   GST_CAT_DEBUG (GST_CAT_CLOCK, "adding entry %p", entry);
458
459   GST_OBJECT_LOCK (clock);
460   /* need to take a ref */
461   gst_clock_id_ref ((GstClockID) entry);
462   /* insert the entry in sorted order */
463   clock->entries = g_list_insert_sorted (clock->entries, entry,
464       gst_clock_id_compare_func);
465
466   /* only need to send the signal if the entry was added to the
467    * front, else the thread is just waiting for another entry and
468    * will get to this entry automatically. */
469   if (clock->entries->data == entry) {
470     GST_CAT_DEBUG (GST_CAT_CLOCK, "send signal");
471     GST_CLOCK_BROADCAST (clock);
472   }
473   GST_OBJECT_UNLOCK (clock);
474
475   return GST_CLOCK_OK;
476 }
477
478 /* unschedule an entry. This will set the state of the entry to GST_CLOCK_UNSCHEDULED
479  * and will signal any thread waiting for entries to recheck their entry.
480  * We cannot really decide if the signal is needed or not because the entry
481  * could be waited on in async or sync mode.
482  *
483  * MT safe.
484  */
485 static void
486 gst_system_clock_id_unschedule (GstClock * clock, GstClockEntry * entry)
487 {
488   GST_CAT_DEBUG (GST_CAT_CLOCK, "unscheduling entry %p", entry);
489
490   GST_OBJECT_LOCK (clock);
491   entry->status = GST_CLOCK_UNSCHEDULED;
492   GST_CAT_DEBUG (GST_CAT_CLOCK, "send signal");
493   GST_CLOCK_BROADCAST (clock);
494   GST_OBJECT_UNLOCK (clock);
495 }