gstclock.c 17.5 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

#include "gst_private.h"
26
#include "gstclock.h"
27 28
#include "gstlog.h"
#include "gstmemchunk.h"
Wim Taymans's avatar
Wim Taymans committed
29

Wim Taymans's avatar
Wim Taymans committed
30
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
31
/* #define GST_WITH_ALLOC_TRACE */
Wim Taymans's avatar
Wim Taymans committed
32 33 34
#include "gsttrace.h"
static GstAllocTrace *_gst_clock_entry_trace;
#endif
Wim Taymans's avatar
Wim Taymans committed
35

36 37
#define DEFAULT_MAX_DIFF	(2 * GST_SECOND)

38 39 40
enum {
  ARG_0,
  ARG_STATS,
41
  ARG_MAX_DIFF,
42 43
};

Wim Taymans's avatar
Wim Taymans committed
44
static GstMemChunk   *_gst_clock_entries_chunk;
Wim Taymans's avatar
Wim Taymans committed
45

46 47
static void		gst_clock_class_init		(GstClockClass *klass);
static void		gst_clock_init			(GstClock *clock);
Wim Taymans's avatar
Wim Taymans committed
48 49
static void 		gst_clock_dispose 		(GObject *object);

50 51 52 53 54
static void             gst_clock_set_property		(GObject *object, guint prop_id, 
							 const GValue *value, GParamSpec *pspec);
static void             gst_clock_get_property		(GObject *object, guint prop_id, 
							 GValue *value, GParamSpec * pspec);
static void		gst_clock_update_stats		(GstClock *clock);
55

56

57 58 59
static GstObjectClass *parent_class = NULL;
/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */

Wim Taymans's avatar
Wim Taymans committed
60
static GstClockID
61 62 63 64
gst_clock_entry_new (GstClock *clock, GstClockTime time, 
		     GstClockTime interval, GstClockEntryType type)
{
  GstClockEntry *entry;
65

66
  entry = gst_mem_chunk_alloc (_gst_clock_entries_chunk);
Wim Taymans's avatar
Wim Taymans committed
67
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
68
  gst_alloc_trace_new (_gst_clock_entry_trace, entry);
Wim Taymans's avatar
Wim Taymans committed
69
#endif
70

71 72 73 74 75
  entry->clock = clock;
  entry->time = time;
  entry->interval = time;
  entry->type = type;
  entry->status = GST_CLOCK_ENTRY_OK;
76

77 78
  return (GstClockID) entry;
}
79

80 81 82 83 84 85 86 87 88 89 90 91 92
/**
 * gst_clock_new_single_shot_id
 * @clock: The clockid to get a single shot notification from
 * @time: the requested time
 *
 * Get an ID from the given clock to trigger a single shot 
 * notification at the requested time.
 *
 * Returns: An id that can be used to request the time notification.
 */
GstClockID
gst_clock_new_single_shot_id (GstClock *clock, GstClockTime time)
{
93 94
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

95 96 97 98 99 100 101
  return gst_clock_entry_new (clock, 
		  	      time, 
			      GST_CLOCK_TIME_NONE, 
			      GST_CLOCK_ENTRY_SINGLE);
}

/**
Wim Taymans's avatar
Wim Taymans committed
102
 * gst_clock_new_periodic_id
103 104 105 106 107 108 109 110 111 112 113 114 115 116
 * @clock: The clockid to get a periodic notification id from
 * @start_time: the requested start time
 * @interval: the requested interval
 *
 * Get an ID from the given clock to trigger a periodic notification.
 * The periodeic notifications will be start at time start_time and
 * will then be fired with the given interval.
 *
 * Returns: An id that can be used to request the time notification.
 */
GstClockID
gst_clock_new_periodic_id (GstClock *clock, GstClockTime start_time,
                           GstClockTime interval)
{
117 118 119 120
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
  g_return_val_if_fail (start_time != GST_CLOCK_TIME_NONE, NULL);
  g_return_val_if_fail (interval != 0, NULL);

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
  return gst_clock_entry_new (clock, 
		  	      start_time, 
			      interval, 
			      GST_CLOCK_ENTRY_PERIODIC);
}

/**
 * gst_clock_id_get_time
 * @id: The clockid to query
 *
 * Get the time of the clock ID
 *
 * Returns: the time of the given clock id
 */
GstClockTime
gst_clock_id_get_time (GstClockID id)
{
  g_return_val_if_fail (id != NULL, GST_CLOCK_TIME_NONE);

  return GST_CLOCK_ENTRY_TIME ((GstClockEntry *)id);
}


/**
 * gst_clock_id_wait
 * @id: The clockid to wait on
 * @jitter: A pointer that will contain the jitter
 *
 * Perform a blocking wait on the given ID. The jitter arg can be
 * NULL
 *
 * Returns: the result of the blocking wait.
 */
GstClockReturn
gst_clock_id_wait (GstClockID id, GstClockTimeDiff *jitter)
156 157
{
  GstClockEntry *entry;
158 159 160
  GstClock *clock;
  GstClockReturn res = GST_CLOCK_UNSUPPORTED;
  GstClockTime requested;
Wim Taymans's avatar
Wim Taymans committed
161
  GstClockClass *cclass;
162 163
  
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
164

165 166
  entry = (GstClockEntry *) id;
  requested = GST_CLOCK_ENTRY_TIME (entry);
167 168

  if (requested == GST_CLOCK_TIME_NONE) {
169
    return GST_CLOCK_TIMEOUT;
170
  }
171

172
  clock = GST_CLOCK_ENTRY_CLOCK (entry);
Wim Taymans's avatar
Wim Taymans committed
173
  cclass = GST_CLOCK_GET_CLASS (clock);
174
  
Wim Taymans's avatar
Wim Taymans committed
175
  if (cclass->wait) {
176
    GstClockTime now;
177 178 179 180
    
    GST_LOCK (clock);
    clock->entries = g_list_prepend (clock->entries, entry);
    GST_UNLOCK (clock);
181

182
    do {
Wim Taymans's avatar
Wim Taymans committed
183
      res = cclass->wait (clock, entry);
184 185 186
    }
    while (res == GST_CLOCK_ENTRY_RESTART);

187 188 189 190
    GST_LOCK (clock);
    clock->entries = g_list_remove (clock->entries, entry);
    GST_UNLOCK (clock);

191 192 193 194 195 196 197 198 199 200 201 202 203 204
    if (jitter) {
      now = gst_clock_get_time (clock);
      *jitter = now - requested;
    }

    if (clock->stats) {
      gst_clock_update_stats (clock);
    }
  }

  return res;
}

/**
Wim Taymans's avatar
Wim Taymans committed
205 206
 * gst_clock_id_wait_async:
 * @id: a #GstClockID to wait on
207 208 209
 * @func: The callback function 
 * @user_data: User data passed in the calback
 *
Wim Taymans's avatar
Wim Taymans committed
210 211
 * Register a callback on the given clockid with the given
 * function and user_data.
212
 *
213
 * Returns: the result of the non blocking wait.
214 215 216 217 218 219 220 221
 */
GstClockReturn
gst_clock_id_wait_async (GstClockID id,
		         GstClockCallback func, gpointer user_data)
{
  GstClockEntry *entry;
  GstClock *clock;
  GstClockReturn res = GST_CLOCK_UNSUPPORTED;
Wim Taymans's avatar
Wim Taymans committed
222
  GstClockClass *cclass;
223 224
  
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
225
  g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
226 227 228 229

  entry = (GstClockEntry *) id;
  clock = entry->clock;

230 231 232 233 234
  if (GST_CLOCK_ENTRY_TIME (entry) == GST_CLOCK_TIME_NONE) {
    (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
    return GST_CLOCK_TIMEOUT;
  }

Wim Taymans's avatar
Wim Taymans committed
235 236 237 238 239 240 241
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->wait_async) {
    entry->func = func;
    entry->user_data = user_data;

    res = cclass->wait_async (clock, entry);
242 243 244 245 246
  }

  return res;
}

247 248 249 250 251 252 253 254
static void
gst_clock_reschedule_func (GstClockEntry *entry)
{
  entry->status = GST_CLOCK_ENTRY_OK;
  
  gst_clock_id_unlock ((GstClockID)entry);
}

255
/**
Wim Taymans's avatar
Wim Taymans committed
256 257
 * gst_clock_id_unschedule:
 * @id: The id to unschedule
258 259 260 261 262 263 264 265
 *
 * Cancel an outstanding async notification request with the given ID.
 */
void
gst_clock_id_unschedule (GstClockID id)
{
  GstClockEntry *entry;
  GstClock *clock;
Wim Taymans's avatar
Wim Taymans committed
266
  GstClockClass *cclass;
267 268 269 270 271
  
  g_return_if_fail (id != NULL);

  entry = (GstClockEntry *) id;
  clock = entry->clock;
272

Wim Taymans's avatar
Wim Taymans committed
273 274 275 276
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unschedule)
    cclass->unschedule (clock, entry);
277 278
}

279
/**
Wim Taymans's avatar
Wim Taymans committed
280
 * gst_clock_id_free:
281 282 283 284 285 286
 * @id: The clockid to free
 *
 * Free the resources held by the given id
 */
void
gst_clock_id_free (GstClockID id)
287
{
288 289
  g_return_if_fail (id != NULL);

Wim Taymans's avatar
Wim Taymans committed
290
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
291
  gst_alloc_trace_free (_gst_clock_entry_trace, id);
Wim Taymans's avatar
Wim Taymans committed
292
#endif
293 294
  gst_mem_chunk_free (_gst_clock_entries_chunk, id);
}
295

296
/**
Wim Taymans's avatar
Wim Taymans committed
297
 * gst_clock_id_unlock:
298 299 300 301 302 303 304 305 306
 * @id: The clockid to unlock
 *
 * Unlock the givan ClockID.
 */
void
gst_clock_id_unlock (GstClockID id)
{
  GstClockEntry *entry;
  GstClock *clock;
Wim Taymans's avatar
Wim Taymans committed
307
  GstClockClass *cclass;
308 309 310 311 312 313
  
  g_return_if_fail (id != NULL);

  entry = (GstClockEntry *) id;
  clock = entry->clock;

Wim Taymans's avatar
Wim Taymans committed
314 315 316 317
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unlock)
    cclass->unlock (clock, entry);
318 319
}

320 321 322 323

/**
 * GstClock abstract base class implementation
 */
324 325
GType
gst_clock_get_type (void)
Wim Taymans's avatar
Wim Taymans committed
326
{
327 328 329 330
  static GType clock_type = 0;

  if (!clock_type) {
    static const GTypeInfo clock_info = {
331
      sizeof (GstClockClass),
332 333 334 335 336
      NULL,
      NULL,
      (GClassInitFunc) gst_clock_class_init,
      NULL,
      NULL,
337
      sizeof (GstClock),
338 339 340 341 342
      4,
      (GInstanceInitFunc) gst_clock_init,
      NULL
    };
    clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock", 
343
		    			 &clock_info,  G_TYPE_FLAG_ABSTRACT);
344 345 346
  }
  return clock_type;
}
347

348 349 350 351 352
static void
gst_clock_class_init (GstClockClass *klass)
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;
353

354 355
  gobject_class = (GObjectClass*) klass;
  gstobject_class = (GstObjectClass*) klass;
356

357
  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
358

Wim Taymans's avatar
Wim Taymans committed
359 360 361
  if (!g_thread_supported ())
    g_thread_init (NULL);

362
  _gst_clock_entries_chunk = gst_mem_chunk_new ("GstClockEntries",
363 364
                     sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
                     G_ALLOC_AND_FREE);
365

Wim Taymans's avatar
Wim Taymans committed
366
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
367
  _gst_clock_entry_trace = gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
Wim Taymans's avatar
Wim Taymans committed
368
#endif
369

Wim Taymans's avatar
Wim Taymans committed
370
  gobject_class->dispose      = GST_DEBUG_FUNCPTR (gst_clock_dispose);
371 372 373 374 375 376
  gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_clock_set_property);
  gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_clock_get_property);

  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATS,
    g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
                          FALSE, G_PARAM_READWRITE));
377 378 379
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_DIFF,
    g_param_spec_int64 ("max-diff", "Max diff", "The maximum amount of time to wait in nanoseconds",
                        0, G_MAXINT64, DEFAULT_MAX_DIFF, G_PARAM_READWRITE));
Wim Taymans's avatar
Wim Taymans committed
380 381
}

382 383
static void
gst_clock_init (GstClock *clock)
Wim Taymans's avatar
Wim Taymans committed
384
{
385 386
  clock->max_diff = DEFAULT_MAX_DIFF;

387 388 389
  clock->speed = 1.0;
  clock->active = FALSE;
  clock->start_time = 0;
390 391
  clock->last_time = 0;
  clock->entries = NULL;
392 393
  clock->flags = 0;
  clock->stats = FALSE;
394 395 396

  clock->active_mutex = g_mutex_new ();
  clock->active_cond = g_cond_new ();
Wim Taymans's avatar
Wim Taymans committed
397 398
}

Wim Taymans's avatar
Wim Taymans committed
399 400 401 402 403 404 405 406 407 408 409
static void
gst_clock_dispose (GObject *object)
{
  GstClock *clock = GST_CLOCK (object);

  g_mutex_free (clock->active_mutex);
  g_cond_free (clock->active_cond);

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

Wim Taymans's avatar
Wim Taymans committed
410 411
/**
 * gst_clock_set_speed
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
412 413
 * @clock: a #GstClock to modify
 * @speed: the speed to set on the clock
Wim Taymans's avatar
Wim Taymans committed
414
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
415
 * Sets the speed on the given clock. 1.0 is the default 
Wim Taymans's avatar
Wim Taymans committed
416
 * speed.
417 418
 *
 * Returns: the new speed of the clock.
Wim Taymans's avatar
Wim Taymans committed
419
 */
420
gdouble
Wim Taymans's avatar
Wim Taymans committed
421 422
gst_clock_set_speed (GstClock *clock, gdouble speed)
{
Wim Taymans's avatar
Wim Taymans committed
423 424
  GstClockClass *cclass;

425 426
  g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);

Wim Taymans's avatar
Wim Taymans committed
427 428 429 430
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->change_speed)
    clock->speed = cclass->change_speed (clock, clock->speed, speed);
Wim Taymans's avatar
Wim Taymans committed
431

432
  return clock->speed;
Wim Taymans's avatar
Wim Taymans committed
433 434 435 436
}

/**
 * gst_clock_get_speed
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
437
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
438
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
439
 * Gets the speed of the given clock.
Wim Taymans's avatar
Wim Taymans committed
440 441 442 443 444 445 446 447 448 449 450 451
 *
 * Returns: the speed of the clock.
 */
gdouble
gst_clock_get_speed (GstClock *clock)
{
  g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);

  return clock->speed;
}

/**
452 453 454
 * gst_clock_set_resolution
 * @clock: The clock set the resolution on
 * @resolution: The resolution to set
Wim Taymans's avatar
Wim Taymans committed
455
 *
456 457 458
 * Set the accuracy of the clock.
 *
 * Returns: the new resolution of the clock.
Wim Taymans's avatar
Wim Taymans committed
459
 */
460 461
guint64
gst_clock_set_resolution (GstClock *clock, guint64 resolution)
Wim Taymans's avatar
Wim Taymans committed
462
{
Wim Taymans's avatar
Wim Taymans committed
463 464
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
465 466
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
  g_return_val_if_fail (resolution != 0, G_GINT64_CONSTANT (0));
467

Wim Taymans's avatar
Wim Taymans committed
468 469 470 471
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->change_resolution)
    clock->resolution = cclass->change_resolution (clock, clock->resolution, resolution);
472

473 474
  return clock->resolution;
}
475

476 477 478 479 480 481 482 483 484 485 486
/**
 * gst_clock_get_resolution
 * @clock: The clock get the resolution of
 *
 * Get the accuracy of the clock.
 *
 * Returns: the resolution of the clock in microseconds.
 */
guint64
gst_clock_get_resolution (GstClock *clock)
{
Wim Taymans's avatar
Wim Taymans committed
487 488
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
489
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
490

Wim Taymans's avatar
Wim Taymans committed
491 492 493 494
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->get_resolution)
    return cclass->get_resolution (clock);
495

Wim Taymans's avatar
Wim Taymans committed
496
  return G_GINT64_CONSTANT (1);
Wim Taymans's avatar
Wim Taymans committed
497 498
}

Wim Taymans's avatar
Wim Taymans committed
499
/**
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
500 501 502
 * gst_clock_set_active
 * @clock: a #GstClock to set state of
 * @active: flag indicating if the clock should be activated (TRUE) or deactivated
Wim Taymans's avatar
Wim Taymans committed
503
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
504
 * Activates or deactivates the clock based on the active parameter.
Wim Taymans's avatar
Wim Taymans committed
505 506
 * As soon as the clock is activated, the time will start ticking.
 */
507
void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
508
gst_clock_set_active (GstClock *clock, gboolean active)
Wim Taymans's avatar
Wim Taymans committed
509
{
Wim Taymans's avatar
Wim Taymans committed
510
  GstClockTime time = G_GINT64_CONSTANT (0);
Wim Taymans's avatar
Wim Taymans committed
511
  GstClockClass *cclass;
512

513 514 515
  g_return_if_fail (GST_IS_CLOCK (clock));

  clock->active = active;
Wim Taymans's avatar
Wim Taymans committed
516 517

  cclass = GST_CLOCK_GET_CLASS (clock);
518
	        
Wim Taymans's avatar
Wim Taymans committed
519 520
  if (cclass->get_internal_time) {
    time = cclass->get_internal_time (clock);
521
  }
522

523 524
  GST_LOCK (clock);
  if (active) {
525 526
    clock->start_time = time - clock->last_time;
    clock->accept_discont = TRUE;
527 528 529
  }
  else {
    clock->last_time = time - clock->start_time;
530
    clock->accept_discont = FALSE;
531
  }
532
  g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
533
  GST_UNLOCK (clock);
534 535

  g_mutex_lock (clock->active_mutex);	
536
  g_cond_broadcast (clock->active_cond);	
537
  g_mutex_unlock (clock->active_mutex);	
538 539
}

Wim Taymans's avatar
Wim Taymans committed
540 541
/**
 * gst_clock_is_active
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
542
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
543 544 545 546 547
 *
 * Checks if the given clock is active.
 * 
 * Returns: TRUE if the clock is active.
 */
548 549
gboolean
gst_clock_is_active (GstClock *clock)
550
{
551
  g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
552

553
  return clock->active;
Wim Taymans's avatar
Wim Taymans committed
554 555
}

556 557 558 559 560 561 562 563 564
/**
 * gst_clock_reset
 * @clock: a #GstClock to reset
 *
 * Reset the clock to time 0.
 */
void
gst_clock_reset (GstClock *clock)
{
Wim Taymans's avatar
Wim Taymans committed
565
  GstClockTime time = G_GINT64_CONSTANT (0);
Wim Taymans's avatar
Wim Taymans committed
566
  GstClockClass *cclass;
567 568 569

  g_return_if_fail (GST_IS_CLOCK (clock));

Wim Taymans's avatar
Wim Taymans committed
570 571 572 573
  cclass = GST_CLOCK_GET_CLASS (clock);
	        
  if (cclass->get_internal_time) {
    time = cclass->get_internal_time (clock);
574 575 576 577 578
  }

  GST_LOCK (clock);
  clock->active = FALSE;
  clock->start_time = time;
Wim Taymans's avatar
Wim Taymans committed
579
  clock->last_time = G_GINT64_CONSTANT (0);
580
  g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
581 582 583
  GST_UNLOCK (clock);
}

Wim Taymans's avatar
Wim Taymans committed
584 585 586 587 588 589
/**
 * gst_clock_handle_discont
 * @clock: a #GstClock to notify of the discontinuity
 * @time: The new time
 *
 * Notifies the clock of a discontinuity in time.
590
 *
Wim Taymans's avatar
Wim Taymans committed
591 592 593 594
 * Returns: TRUE if the clock was updated. It is possible that
 * the clock was not updated by this call because only the first
 * discontinuitity in the pipeline is honoured.
 */
595 596 597
gboolean
gst_clock_handle_discont (GstClock *clock, guint64 time)
{
Wim Taymans's avatar
Wim Taymans committed
598
  GstClockTime itime = G_GINT64_CONSTANT (0);
599 600 601 602

  GST_DEBUG (GST_CAT_CLOCK, "clock discont %" G_GUINT64_FORMAT
		            " %" G_GUINT64_FORMAT " %d",
			    time, clock->start_time, clock->accept_discont);
603

604 605 606
  if (time == GST_CLOCK_TIME_NONE)
    return TRUE;

607 608
  GST_LOCK (clock);
  if (clock->accept_discont) {
Wim Taymans's avatar
Wim Taymans committed
609 610 611 612 613 614
    GstClockClass *cclass;

    cclass = GST_CLOCK_GET_CLASS (clock);
	  
    if (cclass->get_internal_time) {
      itime = cclass->get_internal_time (clock);
615 616 617 618
    }
  }
  else {
    GST_UNLOCK (clock);
619 620 621
    GST_DEBUG (GST_CAT_CLOCK, "clock discont refused %" G_GUINT64_FORMAT
		              " %" G_GUINT64_FORMAT,
			      time, clock->start_time);
622 623 624 625 626 627
    return FALSE;
  }

  clock->start_time = itime - time;
  clock->last_time = time;
  clock->accept_discont = FALSE;
628
  g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
629 630
  GST_UNLOCK (clock);

631 632
  GST_DEBUG (GST_CAT_CLOCK, "new time %" G_GUINT64_FORMAT,
	     gst_clock_get_time (clock));
633

634 635 636
  g_mutex_lock (clock->active_mutex);
  g_cond_broadcast (clock->active_cond);
  g_mutex_unlock (clock->active_mutex);
637 638 639 640

  return TRUE;
}

Wim Taymans's avatar
Wim Taymans committed
641 642
/**
 * gst_clock_get_time
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
643
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
644
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
645
 * Gets the current time of the given clock. The time is always
Wim Taymans's avatar
Wim Taymans committed
646
 * monotonically increasing.
647
 *
Wim Taymans's avatar
Wim Taymans committed
648 649
 * Returns: the time of the clock.
 */
650 651 652
GstClockTime
gst_clock_get_time (GstClock *clock)
{
Wim Taymans's avatar
Wim Taymans committed
653
  GstClockTime ret = G_GINT64_CONSTANT (0);
654

Wim Taymans's avatar
Wim Taymans committed
655
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
656

657
  if (!clock->active) {
Wim Taymans's avatar
Wim Taymans committed
658
    /* clock is not active return previous time */
659 660 661
    ret = clock->last_time;
  }
  else {
Wim Taymans's avatar
Wim Taymans committed
662 663 664 665 666 667
    GstClockClass *cclass;

    cclass = GST_CLOCK_GET_CLASS (clock);

    if (cclass->get_internal_time) {
      ret = cclass->get_internal_time (clock) - clock->start_time;
668 669
    }
    /* make sure the time is increasing, else return last_time */
670
    if ((gint64) ret < (gint64) clock->last_time) {
671 672 673 674 675 676
      ret = clock->last_time;
    }
    else {
      clock->last_time = ret;
    }
  }
677

678
  return ret;
679 680
}

Wim Taymans's avatar
Wim Taymans committed
681 682 683 684 685 686 687 688
/**
 * gst_clock_get_next_id
 * @clock: The clock to query
 *
 * Get the clockid of the next event.
 *
 * Returns: a clockid or NULL is no event is pending.
 */
689 690 691 692 693
GstClockID
gst_clock_get_next_id (GstClock *clock)
{
  GstClockEntry *entry = NULL;

694 695
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

696 697 698 699 700 701 702 703 704
  GST_LOCK (clock);
  if (clock->entries)
    entry = GST_CLOCK_ENTRY (clock->entries->data);
  GST_UNLOCK (clock);

  return (GstClockID *) entry;
}

static void
705
gst_clock_update_stats (GstClock *clock)
706
{
707 708
}

709 710 711
static void
gst_clock_set_property (GObject *object, guint prop_id,
     		        const GValue *value, GParamSpec *pspec)
712
{
713 714 715 716 717 718 719 720
  GstClock *clock;
	     
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      clock->stats = g_value_get_boolean (value);
      break;
721 722 723
    case ARG_MAX_DIFF:
      clock->max_diff = g_value_get_int64 (value);
      break;
724 725 726 727
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
   }
Wim Taymans's avatar
Wim Taymans committed
728
}
729

730 731 732
static void
gst_clock_get_property (GObject *object, guint prop_id, 
			GValue *value, GParamSpec * pspec)
733
{
734 735 736 737 738 739 740 741
  GstClock *clock;
	     
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      g_value_set_boolean (value, clock->stats);
      break;
742 743 744
    case ARG_MAX_DIFF:
      g_value_set_int64 (value, clock->max_diff);
      break;
745 746 747 748
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
   }
749
}