508fd54af676280f1e5d209b2d648722b6dfa76f
[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 "gstelement.h"
29 #include "gstclock.h"
30
31
32 static GstClock *the_system_clock = NULL;
33
34 /**
35  * gst_clock_new:
36  * @name: the name of the new clock
37  *
38  * create a new clock element
39  *
40  * Returns: the new clock element
41  */
42 GstClock*
43 gst_clock_new (gchar *name) 
44 {
45   GstClock *clock = (GstClock *) g_malloc(sizeof(GstClock));
46   
47   clock->name = g_strdup (name);
48   clock->sinkobjects = NULL;
49   clock->sinkmutex = g_mutex_new ();
50   clock->lock = g_mutex_new ();
51   g_mutex_lock (clock->sinkmutex);
52   
53   clock->num = 0;
54   clock->num_locked = 0;
55   clock->locking = FALSE;
56   
57   return clock;
58 }
59
60 GstClock*
61 gst_clock_get_system(void) 
62 {
63   if (the_system_clock == NULL) {
64     the_system_clock = gst_clock_new ("system_clock");
65     gst_clock_reset (the_system_clock);
66   }
67   return the_system_clock;
68 }
69
70 void 
71 gst_clock_register (GstClock *clock, GstObject *obj) 
72 {
73   if ((GST_ELEMENT(obj))->numsrcpads == 0) {
74     GST_DEBUG (0,"gst_clock: setting registered sink object 0x%p\n", obj);
75     clock->sinkobjects = g_list_append (clock->sinkobjects, obj);
76     clock->num++;
77   }
78 }
79
80 void 
81 gst_clock_set (GstClock *clock, GstClockTime time) 
82 {
83   struct timeval tfnow;
84   GstClockTime now;
85
86   gettimeofday (&tfnow, (struct timezone *)NULL);
87   now = tfnow.tv_sec*1000000LL+tfnow.tv_usec;
88   g_mutex_lock (clock->lock);
89   clock->start_time = now - time;
90   g_mutex_unlock (clock->lock);
91   GST_DEBUG (0,"gst_clock: setting clock to %llu %llu %llu\n", time, now, clock->start_time);
92 }
93
94 GstClockTimeDiff 
95 gst_clock_current_diff (GstClock *clock, GstClockTime time)
96 {
97   struct timeval tfnow;
98   GstClockTime now;
99
100   gettimeofday (&tfnow, (struct timezone *)NULL);
101   g_mutex_lock (clock->lock);
102   now = ((guint64)tfnow.tv_sec*1000000LL+tfnow.tv_usec) - (guint64)clock->start_time; 
103   g_mutex_unlock (clock->lock);
104
105   return GST_CLOCK_DIFF (time, now);
106 }
107
108 void 
109 gst_clock_reset (GstClock *clock) 
110 {
111   struct timeval tfnow;
112
113   gettimeofday (&tfnow, (struct timezone *)NULL);
114   g_mutex_lock (clock->lock);
115   clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
116   clock->current_time = clock->start_time;
117   clock->adjust = 0LL;
118   GST_DEBUG (0,"gst_clock: setting start clock %llu\n", clock->start_time);
119   g_mutex_unlock (clock->lock);
120 }
121
122 void 
123 gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj) 
124 {
125   struct timeval tfnow;
126   GstClockTime now;
127   GstClockTimeDiff diff;
128
129
130   gettimeofday (&tfnow, (struct timezone *)NULL);
131   g_mutex_lock (clock->lock);
132   now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time;
133
134   diff = GST_CLOCK_DIFF (time, now);
135   // if we are not behind wait a bit
136   GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld\n", gst_element_get_name(GST_ELEMENT(obj)), time, now, diff);
137    
138   g_mutex_unlock (clock->lock);
139   if (diff > 10000 ) {
140     tfnow.tv_usec = (diff % 1000000);
141     tfnow.tv_sec = diff / 1000000;
142     // FIXME, this piece of code does not work with egcs optimisations on, had to use the following line
143     if (!tfnow.tv_sec) {
144       select(0, NULL, NULL, NULL, &tfnow);
145     }
146     else GST_DEBUG (0,"gst_clock: %s waiting %u %llu %llu %llu seconds\n", gst_element_get_name(GST_ELEMENT(obj)), 
147                     (int)tfnow.tv_sec, now, diff, time);
148   }
149   GST_DEBUG (0,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", gst_element_get_name(GST_ELEMENT(obj)), time, now, diff);
150 }