gstclock.c 5.25 KB
Newer Older
1 2 3 4 5
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *
 * gstclock.c: Clock subsystem for maintaining time sync
Wim Taymans's avatar
Wim Taymans committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <sys/time.h>
24

25
/* #define GST_DEBUG_ENABLED */
26 27
#include "gst_private.h"

28
#include "gstelement.h"
29
#include "gstclock.h"
Wim Taymans's avatar
Wim Taymans committed
30

31

Wim Taymans's avatar
Wim Taymans committed
32 33 34 35 36 37 38 39 40 41
static GstClock *the_system_clock = NULL;

/**
 * gst_clock_new:
 * @name: the name of the new clock
 *
 * create a new clock element
 *
 * Returns: the new clock element
 */
Wim Taymans's avatar
Wim Taymans committed
42
GstClock*
43
gst_clock_new (gchar *name)
Wim Taymans's avatar
Wim Taymans committed
44
{
Wim Taymans's avatar
Wim Taymans committed
45
  GstClock *clock = (GstClock *) g_malloc(sizeof(GstClock));
46

Wim Taymans's avatar
Wim Taymans committed
47
  clock->name = g_strdup (name);
Wim Taymans's avatar
Wim Taymans committed
48
  clock->sinkobjects = NULL;
Wim Taymans's avatar
Wim Taymans committed
49 50 51
  clock->sinkmutex = g_mutex_new ();
  clock->lock = g_mutex_new ();
  g_mutex_lock (clock->sinkmutex);
52

53 54 55
  clock->num = 0;
  clock->num_locked = 0;
  clock->locking = FALSE;
56

Wim Taymans's avatar
Wim Taymans committed
57 58 59
  return clock;
}

60 61 62 63 64 65 66
/**
 * gst_clock_get_system:
 *
 * Get the global system clock
 *
 * Returns: the global clock
 */
Wim Taymans's avatar
Wim Taymans committed
67
GstClock*
68
gst_clock_get_system(void)
Wim Taymans's avatar
Wim Taymans committed
69
{
Wim Taymans's avatar
Wim Taymans committed
70
  if (the_system_clock == NULL) {
Wim Taymans's avatar
Wim Taymans committed
71 72
    the_system_clock = gst_clock_new ("system_clock");
    gst_clock_reset (the_system_clock);
Wim Taymans's avatar
Wim Taymans committed
73 74 75 76
  }
  return the_system_clock;
}

77 78 79 80 81 82 83 84
/**
 * gst_clock_register:
 * @clock: the name of the clock to register to
 * @obj: the object registering to the clock
 *
 * State that an object is interested in listening to the
 * given clock
 */
85 86
void
gst_clock_register (GstClock *clock, GstObject *obj)
Wim Taymans's avatar
Wim Taymans committed
87
{
88
  if ((GST_ELEMENT(obj))->numsrcpads == 0) {
89
    GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting registered sink object 0x%p\n", obj);
Wim Taymans's avatar
Wim Taymans committed
90
    clock->sinkobjects = g_list_append (clock->sinkobjects, obj);
91
    clock->num++;
Wim Taymans's avatar
Wim Taymans committed
92 93 94
  }
}

95 96 97 98 99 100 101
/**
 * gst_clock_set:
 * @clock: The clock to set
 * @time: the time to set
 *
 * Set the time of the given clock to time.
 */
102 103
void
gst_clock_set (GstClock *clock, GstClockTime time)
Wim Taymans's avatar
Wim Taymans committed
104
{
Wim Taymans's avatar
Wim Taymans committed
105
  struct timeval tfnow;
106
  GstClockTime now;
Wim Taymans's avatar
Wim Taymans committed
107

Wim Taymans's avatar
Wim Taymans committed
108
  gettimeofday (&tfnow, (struct timezone *)NULL);
109
  now = tfnow.tv_sec*1000000LL+tfnow.tv_usec;
Wim Taymans's avatar
Wim Taymans committed
110
  g_mutex_lock (clock->lock);
111
  clock->start_time = now - time;
Wim Taymans's avatar
Wim Taymans committed
112
  g_mutex_unlock (clock->lock);
113 114
  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting clock to %llu %llu %llu\n",
             time, now, clock->start_time);
115 116
}

117 118 119 120 121 122 123 124 125 126
/**
 * gst_clock_current_diff:
 * @clock: the clock to calculate the diff against
 * @time: the time
 *
 * Calculate the difference between the given clock and the
 * given time
 *
 * Returns: the clock difference
 */
127
GstClockTimeDiff
Wim Taymans's avatar
Wim Taymans committed
128
gst_clock_current_diff (GstClock *clock, GstClockTime time)
129 130 131 132
{
  struct timeval tfnow;
  GstClockTime now;

Wim Taymans's avatar
Wim Taymans committed
133 134
  gettimeofday (&tfnow, (struct timezone *)NULL);
  g_mutex_lock (clock->lock);
135
  now = ((guint64)tfnow.tv_sec*1000000LL+tfnow.tv_usec) - (guint64)clock->start_time;
Wim Taymans's avatar
Wim Taymans committed
136
  g_mutex_unlock (clock->lock);
137

Wim Taymans's avatar
Wim Taymans committed
138
  return GST_CLOCK_DIFF (time, now);
Wim Taymans's avatar
Wim Taymans committed
139 140
}

141 142 143 144 145 146 147
/**
 * gst_clock_reset:
 * @clock: the clock to reset
 *
 * Reset the given clock. The of the clock will be adjusted back
 * to 0.
 */
148 149
void
gst_clock_reset (GstClock *clock)
Wim Taymans's avatar
Wim Taymans committed
150
{
Wim Taymans's avatar
Wim Taymans committed
151 152
  struct timeval tfnow;

Wim Taymans's avatar
Wim Taymans committed
153 154
  gettimeofday (&tfnow, (struct timezone *)NULL);
  g_mutex_lock (clock->lock);
155
  clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
Wim Taymans's avatar
Wim Taymans committed
156 157
  clock->current_time = clock->start_time;
  clock->adjust = 0LL;
158
  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting start clock %llu\n", clock->start_time);
Wim Taymans's avatar
Wim Taymans committed
159
  g_mutex_unlock (clock->lock);
Wim Taymans's avatar
Wim Taymans committed
160 161
}

162 163 164 165 166 167 168 169
/**
 * gst_clock_wait:
 * @clock: the clock to wait on
 * @time: the time to wait for
 * @obj: the object performing the wait
 *
 * Wait for a specific clock tick on the given clock.
 */
170 171
void
gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
Wim Taymans's avatar
Wim Taymans committed
172
{
Wim Taymans's avatar
Wim Taymans committed
173
  struct timeval tfnow;
174
  GstClockTime now;
Wim Taymans's avatar
Wim Taymans committed
175 176 177
  GstClockTimeDiff diff;


Wim Taymans's avatar
Wim Taymans committed
178 179
  gettimeofday (&tfnow, (struct timezone *)NULL);
  g_mutex_lock (clock->lock);
180
  now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time;
Wim Taymans's avatar
Wim Taymans committed
181

Wim Taymans's avatar
Wim Taymans committed
182
  diff = GST_CLOCK_DIFF (time, now);
183
  /* if we are not behind wait a bit */
184 185
  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld\n",
             GST_OBJECT_NAME (obj), time, now, diff);
186

Wim Taymans's avatar
Wim Taymans committed
187
  g_mutex_unlock (clock->lock);
188 189
  if (diff > 10000 ) {
    tfnow.tv_usec = (diff % 1000000);
Wim Taymans's avatar
Wim Taymans committed
190
    tfnow.tv_sec = diff / 1000000;
191
    /* FIXME, this piece of code does not work with egcs optimisations on, had to use the following line */
192 193 194
    if (!tfnow.tv_sec) {
      select(0, NULL, NULL, NULL, &tfnow);
    }
195 196
    else GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting %u %llu %llu %llu seconds\n",
                    GST_OBJECT_NAME (obj), (int)tfnow.tv_sec, now, diff, time);
Wim Taymans's avatar
Wim Taymans committed
197
  }
198 199
  GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n", 
             GST_OBJECT_NAME (obj), time, now, diff);
Wim Taymans's avatar
Wim Taymans committed
200
}