gstclock.c 17.4 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 38
#define DEFAULT_MAX_DIFF	(2 * GST_SECOND)

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

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

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

51 52 53 54 55
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);
56

57

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

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

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

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

78 79
  return (GstClockID) entry;
}
80

81 82 83 84 85 86 87 88 89 90 91 92 93
/**
 * 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)
{
94 95
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

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

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

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

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

169
  if (! GST_CLOCK_TIME_IS_VALID (requested)) {
170
    GST_CAT_DEBUG (GST_CAT_CLOCK, "invalid time requested, returning _TIMEOUT");
171
    return GST_CLOCK_TIMEOUT;
172
  }
173

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

184
    GST_CAT_DEBUG (GST_CAT_CLOCK, "waiting on clock");
185
    do {
Wim Taymans's avatar
Wim Taymans committed
186
      res = cclass->wait (clock, entry);
187 188
    }
    while (res == GST_CLOCK_ENTRY_RESTART);
189
    GST_CAT_DEBUG (GST_CAT_CLOCK, "done waiting");
190

191 192 193 194
    GST_LOCK (clock);
    clock->entries = g_list_remove (clock->entries, entry);
    GST_UNLOCK (clock);

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

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

234
  if (! GST_CLOCK_TIME_IS_VALID (GST_CLOCK_ENTRY_TIME (entry))) {
235 236 237 238
    (func) (clock, GST_CLOCK_TIME_NONE, id, user_data);
    return GST_CLOCK_TIMEOUT;
  }

Wim Taymans's avatar
Wim Taymans committed
239 240 241 242 243 244 245
  cclass = GST_CLOCK_GET_CLASS (clock);

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

    res = cclass->wait_async (clock, entry);
246 247 248 249 250
  }

  return res;
}

251 252 253 254 255 256 257 258
static void
gst_clock_reschedule_func (GstClockEntry *entry)
{
  entry->status = GST_CLOCK_ENTRY_OK;
  
  gst_clock_id_unlock ((GstClockID)entry);
}

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

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

Wim Taymans's avatar
Wim Taymans committed
277 278 279 280
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unschedule)
    cclass->unschedule (clock, entry);
281 282
}

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

Wim Taymans's avatar
Wim Taymans committed
294
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
295
  gst_alloc_trace_free (_gst_clock_entry_trace, id);
Wim Taymans's avatar
Wim Taymans committed
296
#endif
297 298
  gst_mem_chunk_free (_gst_clock_entries_chunk, id);
}
299

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

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

Wim Taymans's avatar
Wim Taymans committed
318 319 320 321
  cclass = GST_CLOCK_GET_CLASS (clock);

  if (cclass->unlock)
    cclass->unlock (clock, entry);
322 323
}

324 325 326 327

/**
 * GstClock abstract base class implementation
 */
328 329
GType
gst_clock_get_type (void)
Wim Taymans's avatar
Wim Taymans committed
330
{
331 332 333 334
  static GType clock_type = 0;

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

352 353 354 355 356
static void
gst_clock_class_init (GstClockClass *klass)
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;
357

358 359
  gobject_class = (GObjectClass*) klass;
  gstobject_class = (GstObjectClass*) klass;
360

361
  parent_class = g_type_class_ref (GST_TYPE_OBJECT);
362

Wim Taymans's avatar
Wim Taymans committed
363 364 365
  if (!g_thread_supported ())
    g_thread_init (NULL);

366
  _gst_clock_entries_chunk = gst_mem_chunk_new ("GstClockEntries",
367 368
                     sizeof (GstClockEntry), sizeof (GstClockEntry) * 32,
                     G_ALLOC_AND_FREE);
369

Wim Taymans's avatar
Wim Taymans committed
370
#ifndef GST_DISABLE_TRACE
Wim Taymans's avatar
Wim Taymans committed
371
  _gst_clock_entry_trace = gst_alloc_trace_register (GST_CLOCK_ENTRY_TRACE_NAME);
Wim Taymans's avatar
Wim Taymans committed
372
#endif
373

Wim Taymans's avatar
Wim Taymans committed
374
  gobject_class->dispose      = GST_DEBUG_FUNCPTR (gst_clock_dispose);
375 376 377 378 379 380
  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));
381 382 383
  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
384 385
}

386 387
static void
gst_clock_init (GstClock *clock)
Wim Taymans's avatar
Wim Taymans committed
388
{
389 390
  clock->max_diff = DEFAULT_MAX_DIFF;

391 392 393
  clock->speed = 1.0;
  clock->active = FALSE;
  clock->start_time = 0;
394 395
  clock->last_time = 0;
  clock->entries = NULL;
396 397
  clock->flags = 0;
  clock->stats = FALSE;
398 399 400

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

Wim Taymans's avatar
Wim Taymans committed
403 404 405 406 407 408 409 410 411 412 413
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
414 415
/**
 * gst_clock_set_speed
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
416 417
 * @clock: a #GstClock to modify
 * @speed: the speed to set on the clock
Wim Taymans's avatar
Wim Taymans committed
418
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
419
 * Sets the speed on the given clock. 1.0 is the default 
Wim Taymans's avatar
Wim Taymans committed
420
 * speed.
421 422
 *
 * Returns: the new speed of the clock.
Wim Taymans's avatar
Wim Taymans committed
423
 */
424
gdouble
Wim Taymans's avatar
Wim Taymans committed
425 426
gst_clock_set_speed (GstClock *clock, gdouble speed)
{
Wim Taymans's avatar
Wim Taymans committed
427 428
  GstClockClass *cclass;

429 430
  g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);

Wim Taymans's avatar
Wim Taymans committed
431 432 433 434
  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
435

436
  return clock->speed;
Wim Taymans's avatar
Wim Taymans committed
437 438 439 440
}

/**
 * gst_clock_get_speed
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
441
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
442
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
443
 * Gets the speed of the given clock.
Wim Taymans's avatar
Wim Taymans committed
444 445 446 447 448 449 450 451 452 453 454 455
 *
 * 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;
}

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

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

Wim Taymans's avatar
Wim Taymans committed
472 473 474 475
  cclass = GST_CLOCK_GET_CLASS (clock);

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

477 478
  return clock->resolution;
}
479

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

Wim Taymans's avatar
Wim Taymans committed
493
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
494

Wim Taymans's avatar
Wim Taymans committed
495 496 497 498
  cclass = GST_CLOCK_GET_CLASS (clock);

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

Wim Taymans's avatar
Wim Taymans committed
500
  return G_GINT64_CONSTANT (1);
Wim Taymans's avatar
Wim Taymans committed
501 502
}

Wim Taymans's avatar
Wim Taymans committed
503
/**
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
504 505 506
 * 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
507
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
508
 * Activates or deactivates the clock based on the active parameter.
Wim Taymans's avatar
Wim Taymans committed
509 510
 * As soon as the clock is activated, the time will start ticking.
 */
511
void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
512
gst_clock_set_active (GstClock *clock, gboolean active)
Wim Taymans's avatar
Wim Taymans committed
513
{
Wim Taymans's avatar
Wim Taymans committed
514
  GstClockTime time = G_GINT64_CONSTANT (0);
Wim Taymans's avatar
Wim Taymans committed
515
  GstClockClass *cclass;
516

517 518 519
  g_return_if_fail (GST_IS_CLOCK (clock));

  clock->active = active;
Wim Taymans's avatar
Wim Taymans committed
520 521

  cclass = GST_CLOCK_GET_CLASS (clock);
522
	        
Wim Taymans's avatar
Wim Taymans committed
523 524
  if (cclass->get_internal_time) {
    time = cclass->get_internal_time (clock);
525
  }
526

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

  g_mutex_lock (clock->active_mutex);	
540
  g_cond_broadcast (clock->active_cond);	
541
  g_mutex_unlock (clock->active_mutex);	
542 543
}

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

557
  return clock->active;
Wim Taymans's avatar
Wim Taymans committed
558 559
}

560 561 562 563 564 565 566 567 568
/**
 * 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
569
  GstClockTime time = G_GINT64_CONSTANT (0);
Wim Taymans's avatar
Wim Taymans committed
570
  GstClockClass *cclass;
571 572 573

  g_return_if_fail (GST_IS_CLOCK (clock));

Wim Taymans's avatar
Wim Taymans committed
574 575 576 577
  cclass = GST_CLOCK_GET_CLASS (clock);
	        
  if (cclass->get_internal_time) {
    time = cclass->get_internal_time (clock);
578 579 580 581 582
  }

  GST_LOCK (clock);
  clock->active = FALSE;
  clock->start_time = time;
Wim Taymans's avatar
Wim Taymans committed
583
  clock->last_time = G_GINT64_CONSTANT (0);
584
  g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
585 586 587
  GST_UNLOCK (clock);
}

Wim Taymans's avatar
Wim Taymans committed
588 589 590 591 592 593
/**
 * gst_clock_handle_discont
 * @clock: a #GstClock to notify of the discontinuity
 * @time: The new time
 *
 * Notifies the clock of a discontinuity in time.
594
 *
Wim Taymans's avatar
Wim Taymans committed
595 596 597 598
 * 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.
 */
599 600 601
gboolean
gst_clock_handle_discont (GstClock *clock, guint64 time)
{
Wim Taymans's avatar
Wim Taymans committed
602
  GstClockTime itime = G_GINT64_CONSTANT (0);
603
  GstClockClass *cclass = GST_CLOCK_GET_CLASS (clock);;
604

605
  GST_CAT_DEBUG (GST_CAT_CLOCK, "clock discont %" G_GUINT64_FORMAT
606 607
		            " %" G_GUINT64_FORMAT " %d",
			    time, clock->start_time, clock->accept_discont);
608

609
  if (! GST_CLOCK_TIME_IS_VALID (time))
610 611
    return TRUE;

612
  GST_LOCK (clock);
613 614
  if (cclass->get_internal_time) {
    itime = cclass->get_internal_time (clock);
615 616 617 618 619
  }

  clock->start_time = itime - time;
  clock->last_time = time;
  clock->accept_discont = FALSE;
620
  g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
621 622
  GST_UNLOCK (clock);

623
  GST_CAT_DEBUG (GST_CAT_CLOCK, "new time %" G_GUINT64_FORMAT,
624
	     gst_clock_get_time (clock));
625

626 627 628
  g_mutex_lock (clock->active_mutex);
  g_cond_broadcast (clock->active_cond);
  g_mutex_unlock (clock->active_mutex);
629 630 631 632

  return TRUE;
}

Wim Taymans's avatar
Wim Taymans committed
633 634
/**
 * gst_clock_get_time
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
635
 * @clock: a #GstClock to query
Wim Taymans's avatar
Wim Taymans committed
636
 *
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
637
 * Gets the current time of the given clock. The time is always
Wim Taymans's avatar
Wim Taymans committed
638
 * monotonically increasing.
639
 *
Wim Taymans's avatar
Wim Taymans committed
640 641
 * Returns: the time of the clock.
 */
642 643 644
GstClockTime
gst_clock_get_time (GstClock *clock)
{
Wim Taymans's avatar
Wim Taymans committed
645
  GstClockTime ret = G_GINT64_CONSTANT (0);
646

Wim Taymans's avatar
Wim Taymans committed
647
  g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
648

649
  if (!clock->active) {
Wim Taymans's avatar
Wim Taymans committed
650
    /* clock is not active return previous time */
651 652 653
    ret = clock->last_time;
  }
  else {
Wim Taymans's avatar
Wim Taymans committed
654 655 656 657 658 659
    GstClockClass *cclass;

    cclass = GST_CLOCK_GET_CLASS (clock);

    if (cclass->get_internal_time) {
      ret = cclass->get_internal_time (clock) - clock->start_time;
660 661
    }
    /* make sure the time is increasing, else return last_time */
662
    if ((gint64) ret < (gint64) clock->last_time) {
663 664 665 666 667 668
      ret = clock->last_time;
    }
    else {
      clock->last_time = ret;
    }
  }
669

670
  return ret;
671 672
}

Wim Taymans's avatar
Wim Taymans committed
673 674 675 676 677 678 679 680
/**
 * 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.
 */
681 682 683 684 685
GstClockID
gst_clock_get_next_id (GstClock *clock)
{
  GstClockEntry *entry = NULL;

686 687
  g_return_val_if_fail (GST_IS_CLOCK (clock), NULL);

688 689 690 691 692 693 694 695 696
  GST_LOCK (clock);
  if (clock->entries)
    entry = GST_CLOCK_ENTRY (clock->entries->data);
  GST_UNLOCK (clock);

  return (GstClockID *) entry;
}

static void
697
gst_clock_update_stats (GstClock *clock)
698
{
699 700
}

701 702 703
static void
gst_clock_set_property (GObject *object, guint prop_id,
     		        const GValue *value, GParamSpec *pspec)
704
{
705 706 707 708 709 710 711 712
  GstClock *clock;
	     
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      clock->stats = g_value_get_boolean (value);
      break;
713 714 715
    case ARG_MAX_DIFF:
      clock->max_diff = g_value_get_int64 (value);
      break;
716 717 718 719
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
   }
Wim Taymans's avatar
Wim Taymans committed
720
}
721

722 723 724
static void
gst_clock_get_property (GObject *object, guint prop_id, 
			GValue *value, GParamSpec * pspec)
725
{
726 727 728 729 730 731 732 733
  GstClock *clock;
	     
  clock = GST_CLOCK (object);

  switch (prop_id) {
    case ARG_STATS:
      g_value_set_boolean (value, clock->stats);
      break;
734 735 736
    case ARG_MAX_DIFF:
      g_value_set_int64 (value, clock->max_diff);
      break;
737 738 739 740
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
   }
741
}