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

27
#include "gstclock.h"
28
#include "gstinfo.h"
29
#include "gstmemchunk.h"
Wim Taymans's avatar
Wim Taymans committed
30

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

37
#define DEFAULT_EVENT_DIFF	(GST_SECOND)
38 39
#define DEFAULT_MAX_DIFF	(2 * GST_SECOND)

40 41 42
enum {
  ARG_0,
  ARG_STATS,
43 44
  ARG_MAX_DIFF,
  ARG_EVENT_DIFF
45 46
};

Wim Taymans's avatar
Wim Taymans committed
47
static GstMemChunk   *_gst_clock_entries_chunk;
Wim Taymans's avatar
Wim Taymans committed
48

49 50 51
void			gst_clock_id_unlock		(GstClockID id);

  
52 53
static void		gst_clock_class_init		(GstClockClass *klass);
static void		gst_clock_init			(GstClock *clock);
Wim Taymans's avatar
Wim Taymans committed
54 55
static void 		gst_clock_dispose 		(GObject *object);

56 57 58 59 60
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);
61

62

63 64 65
static GstObjectClass *parent_class = NULL;
/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */

Wim Taymans's avatar
Wim Taymans committed
66
static GstClockID
67 68 69 70
gst_clock_entry_new (GstClock *clock, GstClockTime time, 
		     GstClockTime interval, GstClockEntryType type)
{
  GstClockEntry *entry;
71

72
  entry = gst_mem_chunk_alloc (_gst_clock_entries_chunk);
Wim Taymans's avatar
Wim Taymans committed
73
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
74
  gst_alloc_trace_new (_gst_clock_entry_trace, entry);
Wim Taymans's avatar
Wim Taymans committed
75
#endif
76

77 78 79 80 81
  entry->clock = clock;
  entry->time = time;
  entry->interval = time;
  entry->type = type;
  entry->status = GST_CLOCK_ENTRY_OK;
82

83 84
  return (GstClockID) entry;
}
85

86 87 88 89 90 91 92 93 94 95 96 97 98
/**
 * 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)
{
99 100
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

101 102 103 104 105 106 107
  return gst_clock_entry_new (clock, 
		  	      time, 
			      GST_CLOCK_TIME_NONE, 
			      GST_CLOCK_ENTRY_SINGLE);
}

/**
Wim Taymans's avatar
Wim Taymans committed
108
 * gst_clock_new_periodic_id
109 110 111 112 113 114 115 116 117 118 119 120 121 122
 * @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)
{
123
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);
124
  g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_time), NULL);
125 126
  g_return_val_if_fail (interval != 0, NULL);

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 156 157 158 159 160 161
  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)
162 163
{
  GstClockEntry *entry;
164 165 166
  GstClock *clock;
  GstClockReturn res = GST_CLOCK_UNSUPPORTED;
  GstClockTime requested;
Wim Taymans's avatar
Wim Taymans committed
167
  GstClockClass *cclass;
168 169
  
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
170

171 172
  entry = (GstClockEntry *) id;
  requested = GST_CLOCK_ENTRY_TIME (entry);
173

174
  if (! GST_CLOCK_TIME_IS_VALID (requested)) {
175
    GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _TIMEOUT");
176
    return GST_CLOCK_TIMEOUT;
177
  }
178

179
  clock = GST_CLOCK_ENTRY_CLOCK (entry);
Wim Taymans's avatar
Wim Taymans committed
180
  cclass = GST_CLOCK_GET_CLASS (clock);
181
  
Wim Taymans's avatar
Wim Taymans committed
182
  if (cclass->wait) {
183
    GstClockTime now;
184 185 186 187
    
    GST_LOCK (clock);
    clock->entries = g_list_prepend (clock->entries, entry);
    GST_UNLOCK (clock);
188

189
    GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock");
190
    do {
Wim Taymans's avatar
Wim Taymans committed
191
      res = cclass->wait (clock, entry);
192 193
    }
    while (res == GST_CLOCK_ENTRY_RESTART);
194
    GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting");
195

196 197 198 199
    GST_LOCK (clock);
    clock->entries = g_list_remove (clock->entries, entry);
    GST_UNLOCK (clock);

200 201 202 203 204 205 206 207 208 209 210 211 212 213
    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
214 215
 * gst_clock_id_wait_async:
 * @id: a #GstClockID to wait on
216 217 218
 * @func: The callback function 
 * @user_data: User data passed in the calback
 *
Wim Taymans's avatar
Wim Taymans committed
219 220
 * Register a callback on the given clockid with the given
 * function and user_data.
221
 *
222
 * Returns: the result of the non blocking wait.
223 224 225 226 227 228 229 230
 */
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
231
  GstClockClass *cclass;
232 233
  
  g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
234
  g_return_val_if_fail (func != NULL, GST_CLOCK_ERROR);
235 236 237 238

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

239
  if (! GST_CLOCK_TIME_IS_VALID (GST_CLOCK_ENTRY_TIME (entry))) {
240 241 242 243
    (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
    return GST_CLOCK_TIMEOUT;
  }

Wim Taymans's avatar
Wim Taymans committed
244 245 246 247 248 249 250
  cclass = GST_CLOCK_GET_CLASS (clock);

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

    res = cclass->wait_async (clock, entry);
251 252 253 254 255
  }

  return res;
}

256 257 258 259 260 261 262 263
static void
gst_clock_reschedule_func (GstClockEntry *entry)
{
  entry->status = GST_CLOCK_ENTRY_OK;
  
  gst_clock_id_unlock ((GstClockID)entry);
}

264
/**
Wim Taymans's avatar
Wim Taymans committed
265 266
 * gst_clock_id_unschedule:
 * @id: The id to unschedule
267 268 269 270 271 272 273 274
 *
 * 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
275
  GstClockClass *cclass;
276 277 278 279 280
  
  g_return_if_fail (id != NULL);

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

Wim Taymans's avatar
Wim Taymans committed
282 283 284 285
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unschedule)
    cclass->unschedule (clock, entry);
286 287
}

288
/**
Wim Taymans's avatar
Wim Taymans committed
289
 * gst_clock_id_free:
290 291 292 293 294 295
 * @id: The clockid to free
 *
 * Free the resources held by the given id
 */
void
gst_clock_id_free (GstClockID id)
296
{
297 298
  g_return_if_fail (id != NULL);

Wim Taymans's avatar
Wim Taymans committed
299
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
300
  gst_alloc_trace_free (_gst_clock_entry_trace, id);
Wim Taymans's avatar
Wim Taymans committed
301
#endif
302 303
  gst_mem_chunk_free (_gst_clock_entries_chunk, id);
}
304

305
/**
Wim Taymans's avatar
Wim Taymans committed
306
 * gst_clock_id_unlock:
307 308 309 310 311 312 313 314 315
 * @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
316
  GstClockClass *cclass;
317 318 319 320 321 322
  
  g_return_if_fail (id != NULL);

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

Wim Taymans's avatar
Wim Taymans committed
323 324 325 326
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unlock)
    cclass->unlock (clock, entry);
327 328
}

329 330 331 332

/**
 * GstClock abstract base class implementation
 */
333 334
GType
gst_clock_get_type (void)
Wim Taymans's avatar
Wim Taymans committed
335
{
336 337 338 339
  static GType clock_type = 0;

  if (!clock_type) {
    static const GTypeInfo clock_info = {
340
      sizeof (GstClockClass),
341 342 343 344 345
      NULL,
      NULL,
      (GClassInitFunc) gst_clock_class_init,
      NULL,
      NULL,
346
      sizeof (GstClock),
347 348 349 350 351
      4,
      (GInstanceInitFunc) gst_clock_init,
      NULL
    };
    clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock", 
352
		    			 &clock_info,  G_TYPE_FLAG_ABSTRACT);
353 354 355
  }
  return clock_type;
}
356

357 358 359 360 361
static void
gst_clock_class_init (GstClockClass *klass)
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;
362

363 364
  gobject_class = (GObjectClass*) klass;
  gstobject_class = (GstObjectClass*) klass;
365

366
  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
367

Wim Taymans's avatar
Wim Taymans committed
368 369 370
  if (!g_thread_supported ())
    g_thread_init (NULL);

371
  _gst_clock_entries_chunk = gst_mem_chunk_new ("GstClockEntries",
372 373
                     sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
                     G_ALLOC_AND_FREE);
374

Wim Taymans's avatar
Wim Taymans committed
375
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
376
  _gst_clock_entry_trace = gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
Wim Taymans's avatar
Wim Taymans committed
377
#endif
378

Wim Taymans's avatar
Wim Taymans committed
379
  gobject_class->dispose      = GST_DEBUG_FUNCPTR (gst_clock_dispose);
380 381 382 383 384 385
  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));
386 387 388
  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));
389
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EVENT_DIFF,
390 391
    g_param_spec_uint64 ("event-diff", "event diff", 
	"The amount of time that may elapse until 2 events are treated as happening at different times",
392
                        0, G_MAXUINT64, DEFAULT_EVENT_DIFF, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
Wim Taymans's avatar
Wim Taymans committed
393 394
}

395 396
static void
gst_clock_init (GstClock *clock)
Wim Taymans's avatar
Wim Taymans committed
397
{
398 399
  clock->max_diff = DEFAULT_MAX_DIFF;

400
  clock->start_time = 0;
401 402
  clock->last_time = 0;
  clock->entries = NULL;
403 404
  clock->flags = 0;
  clock->stats = FALSE;
405 406 407

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

Wim Taymans's avatar
Wim Taymans committed
410 411 412 413 414 415 416 417 418 419 420
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
421 422
/**
 * gst_clock_set_speed
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
423 424
 * @clock: a #GstClock to modify
 * @speed: the speed to set on the clock
Wim Taymans's avatar
Wim Taymans committed
425
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
426
 * Sets the speed on the given clock. 1.0 is the default 
Wim Taymans's avatar
Wim Taymans committed
427
 * speed.
428 429
 *
 * Returns: the new speed of the clock.
Wim Taymans's avatar
Wim Taymans committed
430
 */
431
gdouble
Wim Taymans's avatar
Wim Taymans committed
432 433
gst_clock_set_speed (GstClock *clock, gdouble speed)
{
434 435
  g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);

436
  GST_WARNING_OBJECT (clock, "called deprecated function");
437
  return 1.0;
Wim Taymans's avatar
Wim Taymans committed
438 439 440 441
}

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

453
  GST_WARNING_OBJECT (clock, "called deprecated function");
454
  return 1.0;
Wim Taymans's avatar
Wim Taymans committed
455 456 457
}

/**
458 459 460
 * gst_clock_set_resolution
 * @clock: The clock set the resolution on
 * @resolution: The resolution to set
Wim Taymans's avatar
Wim Taymans committed
461
 *
462 463 464
 * Set the accuracy of the clock.
 *
 * Returns: the new resolution of the clock.
Wim Taymans's avatar
Wim Taymans committed
465
 */
466 467
guint64
gst_clock_set_resolution (GstClock *clock, guint64 resolution)
Wim Taymans's avatar
Wim Taymans committed
468
{
Wim Taymans's avatar
Wim Taymans committed
469 470
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
471 472
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
  g_return_val_if_fail (resolution != 0, G_GINT64_CONSTANT (0));
473

Wim Taymans's avatar
Wim Taymans committed
474 475 476 477
  cclass = GST_CLOCK_GET_CLASS (clock);

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

479 480
  return clock->resolution;
}
481

482 483 484 485 486 487 488 489 490 491 492
/**
 * 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
493 494
  GstClockClass *cclass;

Wim Taymans's avatar
Wim Taymans committed
495
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
496

Wim Taymans's avatar
Wim Taymans committed
497 498 499 500
  cclass = GST_CLOCK_GET_CLASS (clock);

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

Wim Taymans's avatar
Wim Taymans committed
502
  return G_GINT64_CONSTANT (1);
Wim Taymans's avatar
Wim Taymans committed
503 504
}

Wim Taymans's avatar
Wim Taymans committed
505
/**
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
506 507 508
 * 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
509
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
510
 * Activates or deactivates the clock based on the active parameter.
Wim Taymans's avatar
Wim Taymans committed
511 512
 * As soon as the clock is activated, the time will start ticking.
 */
513
void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
514
gst_clock_set_active (GstClock *clock, gboolean active)
Wim Taymans's avatar
Wim Taymans committed
515
{
516
  g_return_if_fail (GST_IS_CLOCK (clock));
517 518
  
  GST_ERROR_OBJECT (clock, "called deprecated function that does nothing now.");
519

520
  return;
521 522
}

Wim Taymans's avatar
Wim Taymans committed
523 524
/**
 * gst_clock_is_active
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
525
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
526 527 528 529 530
 *
 * Checks if the given clock is active.
 * 
 * Returns: TRUE if the clock is active.
 */
531 532
gboolean
gst_clock_is_active (GstClock *clock)
533
{
534
  g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
535

536 537 538
  GST_WARNING_OBJECT (clock, "called deprecated function.");

  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
539 540
}

541 542 543 544 545 546 547 548 549
/**
 * 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
550
  GstClockTime time = G_GINT64_CONSTANT (0);
Wim Taymans's avatar
Wim Taymans committed
551
  GstClockClass *cclass;
552 553 554

  g_return_if_fail (GST_IS_CLOCK (clock));

555 556
  GST_ERROR_OBJECT (clock, "called deprecated function.");

Wim Taymans's avatar
Wim Taymans committed
557 558 559 560
  cclass = GST_CLOCK_GET_CLASS (clock);
	        
  if (cclass->get_internal_time) {
    time = cclass->get_internal_time (clock);
561 562 563
  }

  GST_LOCK (clock);
564
  //clock->active = FALSE;
565
  clock->start_time = time;
Wim Taymans's avatar
Wim Taymans committed
566
  clock->last_time = G_GINT64_CONSTANT (0);
567
  g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
568 569 570
  GST_UNLOCK (clock);
}

Wim Taymans's avatar
Wim Taymans committed
571 572 573 574 575 576
/**
 * gst_clock_handle_discont
 * @clock: a #GstClock to notify of the discontinuity
 * @time: The new time
 *
 * Notifies the clock of a discontinuity in time.
577
 *
Wim Taymans's avatar
Wim Taymans committed
578 579 580 581
 * 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.
 */
582 583 584
gboolean
gst_clock_handle_discont (GstClock *clock, guint64 time)
{
585
  GST_ERROR_OBJECT (clock, "called deprecated function.");
586

587
  return FALSE;
588 589
}

Wim Taymans's avatar
Wim Taymans committed
590 591
/**
 * gst_clock_get_time
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
592
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
593
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
594
 * Gets the current time of the given clock. The time is always
Wim Taymans's avatar
Wim Taymans committed
595
 * monotonically increasing.
596
 *
Wim Taymans's avatar
Wim Taymans committed
597 598
 * Returns: the time of the clock.
 */
599 600 601
GstClockTime
gst_clock_get_time (GstClock *clock)
{
Wim Taymans's avatar
Wim Taymans committed
602
  GstClockTime ret = G_GINT64_CONSTANT (0);
603
  GstClockClass *cclass;
604

Wim Taymans's avatar
Wim Taymans committed
605
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
606

607
  cclass = GST_CLOCK_GET_CLASS (clock);
Wim Taymans's avatar
Wim Taymans committed
608

609 610 611 612 613 614 615 616 617 618
  if (cclass->get_internal_time) {
    ret = cclass->get_internal_time (clock) - clock->start_time;
  }
  /* 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;
  }
619

620
  return ret;
621 622
}

623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
/**
 * gst_clock_get_event_time:
 * @clock: clock to query
 * 
 * Gets the "event time" of a given clock. An event on the clock happens
 * whenever this function is called. This ensures that multiple events that
 * happen shortly after each other are treated as if they happened at the same
 * time. GStreamer uses to keep state changes of multiple elements in sync.
 *
 * Returns: the time of the event
 */
GstClockTime
gst_clock_get_event_time (GstClock *clock)
{
  GstClockTime time;
  
  g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
  
  time = gst_clock_get_time (clock);

  if (clock->last_event + clock->max_event_diff >= time) {
    GST_LOG_OBJECT (clock, "reporting last event time %"G_GUINT64_FORMAT, 
	clock->last_event);
  } else {
    GST_LOG_OBJECT (clock, "reporting new event time %"G_GUINT64_FORMAT, 
	clock->last_event);
    clock->last_event = time;
  }
  
  return clock->last_event;
}

Wim Taymans's avatar
Wim Taymans committed
655 656 657 658 659 660 661 662
/**
 * 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.
 */
663 664 665 666 667
GstClockID
gst_clock_get_next_id (GstClock *clock)
{
  GstClockEntry *entry = NULL;

668 669
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

670 671 672 673 674 675 676 677 678
  GST_LOCK (clock);
  if (clock->entries)
    entry = GST_CLOCK_ENTRY (clock->entries->data);
  GST_UNLOCK (clock);

  return (GstClockID *) entry;
}

static void
679
gst_clock_update_stats (GstClock *clock)
680
{
681 682
}

683 684 685
static void
gst_clock_set_property (GObject *object, guint prop_id,
     		        const GValue *value, GParamSpec *pspec)
686
{
687 688 689 690 691 692 693
  GstClock *clock;
	     
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      clock->stats = g_value_get_boolean (value);
694
      g_object_notify (object, "stats");
695
      break;
696 697
    case ARG_MAX_DIFF:
      clock->max_diff = g_value_get_int64 (value);
698 699 700 701
      g_object_notify (object, "max-diff");
      break;
    case ARG_EVENT_DIFF:
      clock->max_event_diff = g_value_get_uint64 (value);
702
      g_object_notify (object, "event-diff");
703
      break;
704 705 706 707
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
   }
Wim Taymans's avatar
Wim Taymans committed
708
}
709

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

  switch (prop_id) {
    case ARG_STATS:
      g_value_set_boolean (value, clock->stats);
      break;
722 723 724
    case ARG_MAX_DIFF:
      g_value_set_int64 (value, clock->max_diff);
      break;
725 726 727
    case ARG_EVENT_DIFF:
      g_value_set_uint64 (value, clock->max_event_diff);
      break;
728 729 730 731
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
   }
732
}