42dd6b36de8bcdfe5d127c5591b1658235d7d1ea
[platform/upstream/gstreamer.git] / gst / gstsystemclock.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@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 #include "gstlog.h"
28
29 #include "gstsystemclock.h"
30
31 static GstClock *_the_system_clock = NULL;
32
33 static void                     gst_system_clock_class_init     (GstSystemClockClass *klass);
34 static void                     gst_system_clock_init           (GstSystemClock *clock);
35
36 static GstClockTime             gst_system_clock_get_internal_time      (GstClock *clock);
37 static guint64                  gst_system_clock_get_resolution (GstClock *clock);
38 static GstClockEntryStatus      gst_system_clock_wait           (GstClock *clock, GstClockEntry *entry);
39 static void                     gst_system_clock_unlock         (GstClock *clock, GstClockEntry *entry);
40
41 static GCond    *_gst_sysclock_cond = NULL;
42 static GMutex   *_gst_sysclock_mutex = NULL;
43
44 static GstClockClass *parent_class = NULL;
45 /* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
46
47 GType
48 gst_system_clock_get_type (void)
49 {
50   static GType clock_type = 0;
51
52   if (!clock_type) {
53     static const GTypeInfo clock_info = {
54       sizeof (GstSystemClockClass),
55       NULL,
56       NULL,
57       (GClassInitFunc) gst_system_clock_class_init,
58       NULL,
59       NULL,
60       sizeof (GstSystemClock),
61       4,
62       (GInstanceInitFunc) gst_system_clock_init,
63       NULL
64     };
65     clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstSystemClock", 
66                                          &clock_info, 0);
67   }
68   return clock_type;
69 }
70
71 static void
72 gst_system_clock_class_init (GstSystemClockClass *klass)
73 {
74   GObjectClass *gobject_class;
75   GstObjectClass *gstobject_class;
76   GstClockClass *gstclock_class;
77
78   gobject_class = (GObjectClass*) klass;
79   gstobject_class = (GstObjectClass*) klass;
80   gstclock_class = (GstClockClass*) klass;
81
82   parent_class = g_type_class_ref (GST_TYPE_CLOCK);
83
84   gstclock_class->get_internal_time     = gst_system_clock_get_internal_time;
85   gstclock_class->get_resolution        = gst_system_clock_get_resolution;
86   gstclock_class->wait                  = gst_system_clock_wait;
87   gstclock_class->unlock                = gst_system_clock_unlock;
88
89   _gst_sysclock_cond  = g_cond_new ();
90   _gst_sysclock_mutex = g_mutex_new ();
91 }
92
93 static void
94 gst_system_clock_init (GstSystemClock *clock)
95 {
96 }
97
98 /**
99  * gst_system_clock_obtain 
100  *
101  * Get a handle to the default system clock.
102  *
103  * Returns: the default clock.
104  */
105 GstClock*
106 gst_system_clock_obtain (void)
107 {
108   if (_the_system_clock == NULL) {
109     _the_system_clock = GST_CLOCK (g_object_new (GST_TYPE_SYSTEM_CLOCK, NULL));
110     
111     gst_object_set_name (GST_OBJECT (_the_system_clock), "GstSystemClock");
112
113     gst_object_ref (GST_OBJECT (_the_system_clock));
114     gst_object_sink (GST_OBJECT (_the_system_clock));
115   }
116   return _the_system_clock;
117 }
118
119 static GstClockTime
120 gst_system_clock_get_internal_time (GstClock *clock)
121 {
122   GTimeVal timeval;
123
124   g_get_current_time (&timeval);
125   
126   return GST_TIMEVAL_TO_TIME (timeval);
127 }
128
129 static guint64
130 gst_system_clock_get_resolution (GstClock *clock)
131 {
132   return 1 * GST_USECOND;
133 }
134
135 static GstClockEntryStatus
136 gst_system_clock_wait (GstClock *clock, GstClockEntry *entry)
137 {
138   GstClockEntryStatus res;
139   GstClockTime current, target;
140   gint64 diff;
141
142   current = gst_clock_get_time (clock);
143   diff = GST_CLOCK_ENTRY_TIME (entry) - current;
144
145   if (ABS (diff) > clock->max_diff) {
146     g_warning ("abnormal clock request diff: ABS(%lld) > %lld", diff, clock->max_diff);
147     return GST_CLOCK_ENTRY_EARLY;
148   }
149   
150   target = gst_system_clock_get_internal_time (clock) + diff;
151
152   GST_DEBUG (GST_CAT_CLOCK, "real_target %" G_GUINT64_FORMAT
153                             " target %" G_GUINT64_FORMAT
154                             " now %" G_GUINT64_FORMAT,
155                             target, GST_CLOCK_ENTRY_TIME (entry), current);
156
157   if (((gint64)target) > 0) {
158     GTimeVal tv;
159
160     GST_TIME_TO_TIMEVAL (target, tv);
161     g_mutex_lock (_gst_sysclock_mutex);
162     g_cond_timed_wait (_gst_sysclock_cond, _gst_sysclock_mutex, &tv);
163     g_mutex_unlock (_gst_sysclock_mutex);
164     res = entry->status;
165   }
166   else {
167     res = GST_CLOCK_ENTRY_EARLY;
168   }
169   return res;
170 }
171
172 static void
173 gst_system_clock_unlock (GstClock *clock, GstClockEntry *entry)
174 {
175   g_mutex_lock (_gst_sysclock_mutex);
176   g_cond_broadcast (_gst_sysclock_cond);
177   g_mutex_unlock (_gst_sysclock_mutex);
178 }