This is the audio/video sync release.
[platform/upstream/gstreamer.git] / gst / gstclock.c
1 /* Gnome-Streamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include <sys/time.h>
21 //#define DEBUG_ENABLED
22 #include <gstclock.h>
23
24 static GstClock *the_system_clock = NULL;
25
26 /**
27  * gst_clock_new:
28  * @name: the name of the new clock
29  *
30  * create a new clock element
31  *
32  * Returns: the new clock element
33  */
34 GstClock *gst_clock_new(gchar *name) {
35   GstClock *clock = (GstClock *) g_malloc(sizeof(GstClock));
36   clock->name = g_strdup(name);
37   clock->sinkobjects = NULL;
38   clock->sinkmutex = g_mutex_new();
39   clock->lock = g_mutex_new();
40   g_mutex_lock(clock->sinkmutex);
41   clock->num = 0;
42   clock->num_locked = 0;
43   clock->locking = FALSE;
44   return clock;
45 }
46
47 GstClock *gst_clock_get_system() {
48   if (the_system_clock == NULL) {
49     the_system_clock = gst_clock_new("system_clock");
50     gst_clock_reset(the_system_clock);
51   }
52   return the_system_clock;
53 }
54
55 void gst_clock_register(GstClock *clock, GstObject *obj) {
56   if (GST_IS_SINK(obj)) {
57     DEBUG("gst_clock: setting registered sink object 0x%p\n", obj);
58     clock->sinkobjects = g_list_append(clock->sinkobjects, obj);
59     clock->num++;
60   }
61 }
62
63 void gst_clock_set(GstClock *clock, GstClockTime time) {
64   struct timeval tfnow;
65   GstClockTime now;
66
67   gettimeofday(&tfnow, (struct timezone *)NULL);
68   now = tfnow.tv_sec*1000000LL+tfnow.tv_usec;
69   g_mutex_lock(clock->lock);
70   clock->start_time = now - time;
71   g_mutex_unlock(clock->lock);
72   DEBUG("gst_clock: setting clock to %llu %llu %llu\n", time, now, clock->start_time);
73 }
74
75 GstClockTimeDiff gst_clock_current_diff(GstClock *clock, GstClockTime time)
76 {
77   struct timeval tfnow;
78   GstClockTime now;
79
80   gettimeofday(&tfnow, (struct timezone *)NULL);
81   g_mutex_lock(clock->lock);
82   now = ((guint64)tfnow.tv_sec*1000000LL+tfnow.tv_usec) - (guint64)clock->start_time; 
83   //if (clock->locking) now = 0;
84   g_mutex_unlock(clock->lock);
85
86   //DEBUG("gst_clock: diff with for time %08llu %08lld %08lld %08llu\n", time, now, GST_CLOCK_DIFF(time, now), clock->start_time);
87
88   return GST_CLOCK_DIFF(time, now);
89 }
90
91 void gst_clock_reset(GstClock *clock) {
92   struct timeval tfnow;
93
94   gettimeofday(&tfnow, (struct timezone *)NULL);
95   g_mutex_lock(clock->lock);
96   clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
97   clock->current_time = clock->start_time;
98   clock->adjust = 0LL;
99   DEBUG("gst_clock: setting start clock %llu\n", clock->start_time);
100   //clock->locking = TRUE;
101   g_mutex_unlock(clock->lock);
102 }
103
104 void gst_clock_wait(GstClock *clock, GstClockTime time, GstObject *obj) {
105   struct timeval tfnow;
106   GstClockTime now;
107   GstClockTimeDiff diff;
108   GList *elements;
109
110   //DEBUG("gst_clock: requesting clock object 0x%p %08llu %08llu\n", obj, time, clock->current_time);
111
112   gettimeofday(&tfnow, (struct timezone *)NULL);
113   g_mutex_lock(clock->lock);
114   now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time;
115   //now = clock->current_time + clock->adjust;
116
117   diff = GST_CLOCK_DIFF(time, now);
118   // if we are not behind wait a bit
119   DEBUG("gst_clock: %s waiting for time %08llu %08llu %08lld\n", gst_element_get_name(GST_ELEMENT(obj)), time, now, diff);
120    
121   g_mutex_unlock(clock->lock);
122   if (diff > 10000 ) {
123     tfnow.tv_usec = (diff % 1000000);
124     tfnow.tv_sec = diff / 1000000;
125     // FIXME, this piece of code does not work with egcs optimisations on, had to use the following line
126     if (!tfnow.tv_sec) {
127       select(0, NULL, NULL, NULL, &tfnow);
128     }
129     else fprintf(stderr, "gst_clock: waiting %u %llu %llu %llu seconds\n", (int)tfnow.tv_sec, now, diff, time);
130     //DEBUG("gst_clock: 0x%p waiting for time %llu %llu %lld %llu\n", obj, time, target, diff, now);
131     //DEBUG("waiting %d.%08d\n",tfnow.tv_sec, tfnow.tv_usec);
132     //DEBUG("gst_clock: 0x%p waiting done time %llu \n", obj, time);
133   }
134   DEBUG("gst_clock: %s waiting for time %08llu %08llu %08lld done \n", gst_element_get_name(GST_ELEMENT(obj)), time, now, diff);
135  // clock->current_time = clock->start_time + time;
136   //gst_clock_set(clock, time);
137
138 }