gstclock.c 16.2 KB
Newer Older
1 2 3
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
4
 *                    2004 Wim Taymans <wim@fluendo.com>
5 6
 *
 * gstclock.c: Clock subsystem for maintaining time sync
Wim Taymans's avatar
Wim Taymans committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * 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.
 */
23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**
 * SECTION:gstclock
 * @short_description: Abstract class for global clocks
 * @see_also: #GstSystemClock
 *
 * GStreamer uses a global clock to synchronise the plugins in a pipeline.
 * Different clock implementations are possible by implementing this abstract
 * base class.
 *
 * The clock time is always measured in nanoseconds and always increases. The
 * pipeline uses the clock to calculate the stream time.
 * Usually all renderers sync to the global clock so that the clock is always 
 * a good measure of the current playback time in the pipeline.
 */
37
#include <time.h>
38 39

#include "gst_private.h"
40

41
#include "gstclock.h"
42
#include "gstinfo.h"
43
#include "gstutils.h"
Wim Taymans's avatar
Wim Taymans committed
44

Wim Taymans's avatar
Wim Taymans committed
45
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
46
/* #define GST_WITH_ALLOC_TRACE */
Wim Taymans's avatar
Wim Taymans committed
47 48 49
#include "gsttrace.h"
static GstAllocTrace *_gst_clock_entry_trace;
#endif
Wim Taymans's avatar
Wim Taymans committed
50

51
#define DEFAULT_EVENT_DIFF	(GST_SECOND)
52 53
#define DEFAULT_MAX_DIFF	(2 * GST_SECOND)

54 55
enum
{
56 57
  ARG_0,
  ARG_STATS,
58 59
  ARG_MAX_DIFF,
  ARG_EVENT_DIFF
60 61
};

62 63
static void gst_clock_class_init (GstClockClass * klass);
static void gst_clock_init (GstClock * clock);
Wim Taymans's avatar
Wim Taymans committed
64
static void gst_clock_finalize (GObject * object);
Wim Taymans's avatar
Wim Taymans committed
65

66 67 68 69 70
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);
71

72

73
static GstObjectClass *parent_class = NULL;
74

75 76
/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */

Wim Taymans's avatar
Wim Taymans committed
77
static GstClockID
78 79
gst_clock_entry_new (GstClock * clock, GstClockTime time,
    GstClockTime interval, GstClockEntryType type)
80 81
{
  GstClockEntry *entry;
82

83
  entry = g_malloc0 (sizeof (GstClockEntry));
Wim Taymans's avatar
Wim Taymans committed
84
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
85
  gst_alloc_trace_new (_gst_clock_entry_trace, entry);
Wim Taymans's avatar
Wim Taymans committed
86
#endif
87 88
  GST_CAT_DEBUG (GST_CAT_CLOCK, "created entry %p, time %" GST_TIME_FORMAT,
      entry, GST_TIME_ARGS (time));
89

90
  gst_atomic_int_set (&entry->refcount, 1);
91 92
  entry->clock = clock;
  entry->time = time;
93
  entry->interval = interval;
94
  entry->type = type;
95
  entry->status = GST_CLOCK_BUSY;
96

97 98
  return (GstClockID) entry;
}
99

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
/**
 * gst_clock_id_ref:
 * @id: The clockid to ref
 *
 * Increase the refcount of the given clockid.
 *
 * Returns: The same #GstClockID with increased refcount.
 *
 * MT safe.
 */
GstClockID
gst_clock_id_ref (GstClockID id)
{
  g_return_val_if_fail (id != NULL, NULL);

115
  g_atomic_int_inc (&((GstClockEntry *) id)->refcount);
116 117 118 119 120 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

  return id;
}

static void
_gst_clock_id_free (GstClockID id)
{
  g_return_if_fail (id != NULL);

  GST_CAT_DEBUG (GST_CAT_CLOCK, "freed entry %p", id);

#ifndef GST_DISABLE_TRACE
  gst_alloc_trace_free (_gst_clock_entry_trace, id);
#endif
}

/**
 * gst_clock_id_unref:
 * @id: The clockid to unref
 *
 * Unref the given clockid. When the refcount reaches 0 the
 * #GstClockID will be freed.
 *
 * MT safe.
 */
void
gst_clock_id_unref (GstClockID id)
{
  gint zero;

  g_return_if_fail (id != NULL);

148
  zero = g_atomic_int_dec_and_test (&((GstClockEntry *) id)->refcount);
149 150 151 152 153 154
  /* if we ended up with the refcount at zero, free the id */
  if (zero) {
    _gst_clock_id_free (id);
  }
}

155 156 157 158 159
/**
 * gst_clock_new_single_shot_id
 * @clock: The clockid to get a single shot notification from
 * @time: the requested time
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
160
 * Get an ID from the given clock to trigger a single shot
161 162
 * notification at the requested time. The single shot id should be
 * unreffed after usage.
163 164
 *
 * Returns: An id that can be used to request the time notification.
165 166
 *
 * MT safe.
167 168
 */
GstClockID
169
gst_clock_new_single_shot_id (GstClock * clock, GstClockTime time)
170
{
171 172
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

173 174
  return gst_clock_entry_new (clock,
      time, GST_CLOCK_TIME_NONE, GST_CLOCK_ENTRY_SINGLE);
175 176 177
}

/**
Wim Taymans's avatar
Wim Taymans committed
178
 * gst_clock_new_periodic_id
179 180 181 182 183 184
 * @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
185 186
 * will then be fired with the given interval. The id should be unreffed
 * after usage.
187 188
 *
 * Returns: An id that can be used to request the time notification.
189 190
 *
 * MT safe.
191 192
 */
GstClockID
193 194
gst_clock_new_periodic_id (GstClock * clock, GstClockTime start_time,
    GstClockTime interval)
195
{
196
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
197
  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_time), NULL);
198 199
  g_return_val_if_fail (interval != 0, NULL);

200 201
  return gst_clock_entry_new (clock,
      start_time, interval, GST_CLOCK_ENTRY_PERIODIC);
202 203
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
/**
 * gst_clock_id_compare_func
 * @id1: A clockid
 * @id2: A clockid to compare with
 *
 * Compares the two GstClockID instances. This function can be used
 * as a GCompareFunc when sorting ids.
 *
 * Returns: negative value if a < b; zero if a = b; positive value if a > b
 *
 * MT safe.
 */
gint
gst_clock_id_compare_func (gconstpointer id1, gconstpointer id2)
{
  GstClockEntry *entry1, *entry2;

  entry1 = (GstClockEntry *) id1;
  entry2 = (GstClockEntry *) id2;

  if (GST_CLOCK_ENTRY_TIME (entry1) > GST_CLOCK_ENTRY_TIME (entry2)) {
    return 1;
  }
  if (GST_CLOCK_ENTRY_TIME (entry1) < GST_CLOCK_ENTRY_TIME (entry2)) {
    return -1;
  }

  return entry1 - entry2;
}

234 235 236 237 238 239
/**
 * gst_clock_id_get_time
 * @id: The clockid to query
 *
 * Get the time of the clock ID
 *
240 241 242
 * Returns: the time of the given clock id.
 *
 * MT safe.
243 244 245 246 247 248
 */
GstClockTime
gst_clock_id_get_time (GstClockID id)
{
  g_return_val_if_fail (id != NULL, GST_CLOCK_TIME_NONE);

249
  return GST_CLOCK_ENTRY_TIME ((GstClockEntry *) id);
250 251 252 253 254 255 256 257 258
}


/**
 * 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
259
 * NULL.
260 261
 *
 * Returns: the result of the blocking wait.
262 263
 *
 * MT safe.
264 265
 */
GstClockReturn
266
gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter)
267 268
{
  GstClockEntry *entry;
269
  GstClock *clock;
270
  GstClockReturn res;
271
  GstClockTime requested;
Wim Taymans's avatar
Wim Taymans committed
272
  GstClockClass *cclass;
273

274
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
275

276 277
  entry = (GstClockEntry *) id;
  requested = GST_CLOCK_ENTRY_TIME (entry);
278

279 280 281 282 283
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
    goto invalid_time;

  if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
    goto unscheduled;
284

285
  clock = GST_CLOCK_ENTRY_CLOCK (entry);
Wim Taymans's avatar
Wim Taymans committed
286
  cclass = GST_CLOCK_GET_CLASS (clock);
287

288
  if (G_LIKELY (cclass->wait)) {
289

290 291 292
    GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock entry %p", id);
    res = cclass->wait (clock, entry);
    GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting entry %p", id);
293

294
    if (jitter) {
295 296
      GstClockTime now = gst_clock_get_time (clock);

297 298
      *jitter = now - requested;
    }
299 300 301
    if (entry->type == GST_CLOCK_ENTRY_PERIODIC) {
      entry->time += entry->interval;
    }
302 303 304 305

    if (clock->stats) {
      gst_clock_update_stats (clock);
    }
306 307
  } else {
    res = GST_CLOCK_UNSUPPORTED;
308 309
  }
  return res;
310 311 312 313 314 315 316 317 318 319 320 321

  /* ERRORS */
invalid_time:
  {
    GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
    return GST_CLOCK_BADTIME;
  }
unscheduled:
  {
    GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was unscheduled return _UNSCHEDULED");
    return GST_CLOCK_UNSCHEDULED;
  }
322 323 324
}

/**
Wim Taymans's avatar
Wim Taymans committed
325 326
 * gst_clock_id_wait_async:
 * @id: a #GstClockID to wait on
327 328 329
 * @func: The callback function 
 * @user_data: User data passed in the calback
 *
Wim Taymans's avatar
Wim Taymans committed
330
 * Register a callback on the given clockid with the given
331 332 333 334
 * function and user_data. When passing an id with an invalid
 * time to this function, the callback will be called immediatly
 * with  a time set to GST_CLOCK_TIME_NONE. The callback will
 * be called when the time of the id has been reached.
335
 *
336
 * Returns: the result of the non blocking wait.
337 338
 *
 * MT safe.
339 340 341
 */
GstClockReturn
gst_clock_id_wait_async (GstClockID id,
342
    GstClockCallback func, gpointer user_data)
343 344 345
{
  GstClockEntry *entry;
  GstClock *clock;
346
  GstClockReturn res;
Wim Taymans's avatar
Wim Taymans committed
347
  GstClockClass *cclass;
348
  GstClockTime requested;
349

350
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
351
  g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
352 353

  entry = (GstClockEntry *) id;
354 355
  requested = GST_CLOCK_ENTRY_TIME (entry);
  clock = GST_CLOCK_ENTRY_CLOCK (entry);
356

357 358 359 360 361
  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (requested)))
    goto invalid_time;

  if (G_UNLIKELY (entry->status == GST_CLOCK_UNSCHEDULED))
    goto unscheduled;
362

Wim Taymans's avatar
Wim Taymans committed
363 364 365 366 367 368 369
  cclass = GST_CLOCK_GET_CLASS (clock);

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

    res = cclass->wait_async (clock, entry);
370 371
  } else {
    res = GST_CLOCK_UNSUPPORTED;
372 373 374
  }
  return res;

375 376 377 378 379 380 381 382 383 384 385 386
  /* ERRORS */
invalid_time:
  {
    (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
    GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _BADTIME");
    return GST_CLOCK_BADTIME;
  }
unscheduled:
  {
    GST_CAT_DEBUG (GST_CAT_CLOCK, "entry was unscheduled return _UNSCHEDULED");
    return GST_CLOCK_UNSCHEDULED;
  }
387 388
}

389
/**
Wim Taymans's avatar
Wim Taymans committed
390 391
 * gst_clock_id_unschedule:
 * @id: The id to unschedule
392
 *
393 394 395 396 397 398
 * Cancel an outstanding request with the given ID. This can either
 * be an outstanding async notification or a pending sync notification.
 * After this call, the @id cannot be used anymore to receive sync or
 * async notifications, you need to create a new GstClockID.
 *
 * MT safe.
399 400 401 402 403 404
 */
void
gst_clock_id_unschedule (GstClockID id)
{
  GstClockEntry *entry;
  GstClock *clock;
Wim Taymans's avatar
Wim Taymans committed
405
  GstClockClass *cclass;
406

407 408 409 410
  g_return_if_fail (id != NULL);

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

Wim Taymans's avatar
Wim Taymans committed
412 413 414 415
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unschedule)
    cclass->unschedule (clock, entry);
416 417
}

418 419 420 421

/**
 * GstClock abstract base class implementation
 */
422 423
GType
gst_clock_get_type (void)
Wim Taymans's avatar
Wim Taymans committed
424
{
425 426 427 428
  static GType clock_type = 0;

  if (!clock_type) {
    static const GTypeInfo clock_info = {
429
      sizeof (GstClockClass),
430 431 432 433 434
      NULL,
      NULL,
      (GClassInitFunc) gst_clock_class_init,
      NULL,
      NULL,
435
      sizeof (GstClock),
436
      0,
437 438 439
      (GInstanceInitFunc) gst_clock_init,
      NULL
    };
440

441
    clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock",
442
        &clock_info, G_TYPE_FLAG_ABSTRACT);
443 444 445
  }
  return clock_type;
}
446

447
static void
448
gst_clock_class_init (GstClockClass * klass)
449 450 451
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;
452

453 454
  gobject_class = (GObjectClass *) klass;
  gstobject_class = (GstObjectClass *) klass;
455

456
  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
457

Wim Taymans's avatar
Wim Taymans committed
458 459 460
  if (!g_thread_supported ())
    g_thread_init (NULL);

Wim Taymans's avatar
Wim Taymans committed
461
#ifndef GST_DISABLE_TRACE
462 463
  _gst_clock_entry_trace =
      gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
Wim Taymans's avatar
Wim Taymans committed
464
#endif
465

Wim Taymans's avatar
Wim Taymans committed
466
  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_clock_finalize);
467 468 469 470
  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,
471
      g_param_spec_boolean ("stats", "Stats", "Enable clock stats",
472
          FALSE, G_PARAM_READWRITE));
Wim Taymans's avatar
Wim Taymans committed
473 474
}

475
static void
476
gst_clock_init (GstClock * clock)
Wim Taymans's avatar
Wim Taymans committed
477
{
478
  clock->adjust = 0;
479 480
  clock->last_time = 0;
  clock->entries = NULL;
481
  clock->entries_changed = g_cond_new ();
482 483
  clock->flags = 0;
  clock->stats = FALSE;
Wim Taymans's avatar
Wim Taymans committed
484 485
}

Wim Taymans's avatar
Wim Taymans committed
486
static void
Wim Taymans's avatar
Wim Taymans committed
487
gst_clock_finalize (GObject * object)
Wim Taymans's avatar
Wim Taymans committed
488 489 490
{
  GstClock *clock = GST_CLOCK (object);

491
  g_cond_free (clock->entries_changed);
Wim Taymans's avatar
Wim Taymans committed
492

Wim Taymans's avatar
Wim Taymans committed
493
  G_OBJECT_CLASS (parent_class)->finalize (object);
Wim Taymans's avatar
Wim Taymans committed
494 495
}

Wim Taymans's avatar
Wim Taymans committed
496
/**
497 498 499
 * gst_clock_set_resolution
 * @clock: The clock set the resolution on
 * @resolution: The resolution to set
Wim Taymans's avatar
Wim Taymans committed
500
 *
501 502 503
 * Set the accuracy of the clock.
 *
 * Returns: the new resolution of the clock.
Wim Taymans's avatar
Wim Taymans committed
504
 */
505
guint64
506
gst_clock_set_resolution (GstClock * clock, guint64 resolution)
Wim Taymans's avatar
Wim Taymans committed
507
{
Wim Taymans's avatar
Wim Taymans committed
508 509
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
510 511
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
  g_return_val_if_fail (resolution != 0, G_GINT64_CONSTANT (0));
512

Wim Taymans's avatar
Wim Taymans committed
513 514 515
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->change_resolution)
516
    clock->resolution =
517
        cclass->change_resolution (clock, clock->resolution, resolution);
518

519 520
  return clock->resolution;
}
521

522 523 524 525 526 527 528
/**
 * 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.
529 530
 *
 * MT safe.
531 532
 */
guint64
533
gst_clock_get_resolution (GstClock * clock)
534
{
Wim Taymans's avatar
Wim Taymans committed
535 536
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
537
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
538

Wim Taymans's avatar
Wim Taymans committed
539 540 541 542
  cclass = GST_CLOCK_GET_CLASS (clock);

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

Wim Taymans's avatar
Wim Taymans committed
544
  return G_GINT64_CONSTANT (1);
Wim Taymans's avatar
Wim Taymans committed
545 546
}

Wim Taymans's avatar
Wim Taymans committed
547
/**
548 549 550
 * gst_clock_adjust_unlocked
 * @clock: a #GstClock to use
 * @internal: a clock time
Wim Taymans's avatar
Wim Taymans committed
551
 *
552 553 554
 * Converts the given @internal clock time to the real time, adjusting
 * and making sure that the returned time is increasing.
 * This function should be called with the clock lock held.
Wim Taymans's avatar
Wim Taymans committed
555
 *
556
 * Returns: the converted time of the clock.
557
 *
558
 * MT safe.
559
 */
560 561
GstClockTime
gst_clock_adjust_unlocked (GstClock * clock, GstClockTime internal)
562
{
563
  GstClockTime ret;
564

565 566 567 568 569 570
  ret = internal + clock->adjust;
  /* make sure the time is increasing, else return last_time */
  if ((gint64) ret < (gint64) clock->last_time) {
    ret = clock->last_time;
  } else {
    clock->last_time = ret;
571
  }
572
  return ret;
573 574
}

Wim Taymans's avatar
Wim Taymans committed
575 576
/**
 * gst_clock_get_time
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
577
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
578
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
579
 * Gets the current time of the given clock. The time is always
Wim Taymans's avatar
Wim Taymans committed
580
 * monotonically increasing.
581
 *
582 583 584 585
 * Returns: the time of the clock. Or GST_CLOCK_TIME_NONE when
 * giving wrong input.
 *
 * MT safe.
Wim Taymans's avatar
Wim Taymans committed
586
 */
587
GstClockTime
588
gst_clock_get_time (GstClock * clock)
589
{
590
  GstClockTime ret;
591
  GstClockClass *cclass;
592

593
  g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
594

595
  cclass = GST_CLOCK_GET_CLASS (clock);
Wim Taymans's avatar
Wim Taymans committed
596

597
  if (cclass->get_internal_time) {
598
    ret = cclass->get_internal_time (clock);
599
  } else {
600
    ret = G_GINT64_CONSTANT (0);
601
  }
602 603
  GST_CAT_DEBUG (GST_CAT_CLOCK, "internal time %" GST_TIME_FORMAT,
      GST_TIME_ARGS (ret));
604

605 606 607
  GST_LOCK (clock);
  ret = gst_clock_adjust_unlocked (clock, ret);
  GST_UNLOCK (clock);
608

609 610
  GST_CAT_DEBUG (GST_CAT_CLOCK, "adjusted time %" GST_TIME_FORMAT,
      GST_TIME_ARGS (ret));
611

612
  return ret;
613 614
}

Wim Taymans's avatar
Wim Taymans committed
615
/**
616 617 618
 * gst_clock_set_time_adjust
 * @clock: a #GstClock to adjust
 * @adjust: the adjust value
Wim Taymans's avatar
Wim Taymans committed
619
 *
620 621 622 623 624
 * Adjusts the current time of the clock with the adjust value.
 * A positive value moves the clock forwards and a backwards value
 * moves it backwards. Note that _get_time() always returns 
 * increasing values so when you move the clock backwards, _get_time()
 * will report the previous value until the clock catches up.
Wim Taymans's avatar
Wim Taymans committed
625
 *
626
 * MT safe.
Wim Taymans's avatar
Wim Taymans committed
627
 */
628 629
void
gst_clock_set_time_adjust (GstClock * clock, GstClockTime adjust)
630
{
631
  g_return_if_fail (GST_IS_CLOCK (clock));
632

633
  GST_LOCK (clock);
634
  clock->adjust = adjust;
635 636 637 638
  GST_UNLOCK (clock);
}

static void
639
gst_clock_update_stats (GstClock * clock)
640
{
641 642
}

643
static void
644 645
gst_clock_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
646
{
647
  GstClock *clock;
648

649 650 651 652 653
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      clock->stats = g_value_get_boolean (value);
654
      g_object_notify (object, "stats");
655 656 657 658
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
659
  }
Wim Taymans's avatar
Wim Taymans committed
660
}
661

662
static void
663 664
gst_clock_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
665
{
666
  GstClock *clock;
667

668 669 670 671 672 673 674 675 676
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      g_value_set_boolean (value, clock->stats);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
677
  }
678
}