Port gtk-doc comments to their equivalent markdown syntax
[platform/upstream/gstreamer.git] / libs / gst / check / gsttestclock.c
1 /* GstTestClock - A deterministic clock for GStreamer unit tests
2  *
3  * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
4  * Copyright (C) 2012 Sebastian Rasmussen <sebastian.rasmussen@axis.com>
5  * Copyright (C) 2012 Havard Graff <havard@pexip.com>
6  * Copyright (C) 2013 Haakon Sporsheim <haakon@pexip.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:gsttestclock
26  * @title: GstTestClock
27  * @short_description: Controllable, deterministic clock for GStreamer unit tests
28  * @see_also: #GstSystemClock, #GstClock
29  *
30  * GstTestClock is an implementation of #GstClock which has different
31  * behaviour compared to #GstSystemClock. Time for #GstSystemClock advances
32  * according to the system time, while time for #GstTestClock changes only
33  * when gst_test_clock_set_time() or gst_test_clock_advance_time() are
34  * called. #GstTestClock provides unit tests with the possibility to
35  * precisely advance the time in a deterministic manner, independent of the
36  * system time or any other external factors.
37  *
38  * ## Advancing the time of a #GstTestClock
39  *
40  * |[<!-- language="C" -->
41  *   #include <gst/gst.h>
42  *   #include <gst/check/gsttestclock.h>
43  *
44  *   GstClock *clock;
45  *   GstTestClock *test_clock;
46  *
47  *   clock = gst_test_clock_new ();
48  *   test_clock = GST_TEST_CLOCK (clock);
49  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
50  *   gst_test_clock_advance_time ( test_clock, 1 * GST_SECOND);
51  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
52  *   g_usleep (10 * G_USEC_PER_SEC);
53  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
54  *   gst_test_clock_set_time (test_clock, 42 * GST_SECOND);
55  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
56  *   ...
57  * ]|
58  *
59  * #GstClock allows for setting up single shot or periodic clock notifications
60  * as well as waiting for these notifications synchronously (using
61  * gst_clock_id_wait()) or asynchronously (using gst_clock_id_wait_async() or
62  * gst_clock_id_wait_async()). This is used by many GStreamer elements,
63  * among them #GstBaseSrc and #GstBaseSink.
64  *
65  * #GstTestClock keeps track of these clock notifications. By calling
66  * gst_test_clock_wait_for_next_pending_id() or
67  * gst_test_clock_wait_for_multiple_pending_ids() a unit tests may wait for the
68  * next one or several clock notifications to be requested. Additionally unit
69  * tests may release blocked waits in a controlled fashion by calling
70  * gst_test_clock_process_next_clock_id(). This way a unit test can control the
71  * inaccuracy (jitter) of clock notifications, since the test can decide to
72  * release blocked waits when the clock time has advanced exactly to, or past,
73  * the requested clock notification time.
74  *
75  * There are also interfaces for determining if a notification belongs to a
76  * #GstTestClock or not, as well as getting the number of requested clock
77  * notifications so far.
78  *
79  * N.B.: When a unit test waits for a certain amount of clock notifications to
80  * be requested in gst_test_clock_wait_for_next_pending_id() or
81  * gst_test_clock_wait_for_multiple_pending_ids() then these functions may block
82  * for a long time. If they block forever then the expected clock notifications
83  * were never requested from #GstTestClock, and so the assumptions in the code
84  * of the unit test are wrong. The unit test case runner in gstcheck is
85  * expected to catch these cases either by the default test case timeout or the
86  * one set for the unit test by calling tcase_set_timeout\(\).
87  *
88  * The sample code below assumes that the element under test will delay a
89  * buffer pushed on the source pad by some latency until it arrives on the sink
90  * pad. Moreover it is assumed that the element will at some point call
91  * gst_clock_id_wait() to synchronously wait for a specific time. The first
92  * buffer sent will arrive exactly on time only delayed by the latency. The
93  * second buffer will arrive a little late (7ms) due to simulated jitter in the
94  * clock notification.
95  *
96  * ## Demonstration of how to work with clock notifications and #GstTestClock
97  *
98  * |[<!-- language="C" -->
99  *   #include <gst/gst.h>
100  *   #include <gst/check/gstcheck.h>
101  *   #include <gst/check/gsttestclock.h>
102  *
103  *   GstClockTime latency;
104  *   GstElement *element;
105  *   GstPad *srcpad;
106  *   GstClock *clock;
107  *   GstTestClock *test_clock;
108  *   GstBuffer buf;
109  *   GstClockID pending_id;
110  *   GstClockID processed_id;
111  *
112  *   latency = 42 * GST_MSECOND;
113  *   element = create_element (latency, ...);
114  *   srcpad = get_source_pad (element);
115  *
116  *   clock = gst_test_clock_new ();
117  *   test_clock = GST_TEST_CLOCK (clock);
118  *   gst_element_set_clock (element, clock);
119  *
120  *   GST_INFO ("Set time, create and push the first buffer\n");
121  *   gst_test_clock_set_time (test_clock, 0);
122  *   buf = create_test_buffer (gst_clock_get_time (clock), ...);
123  *   gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);
124  *
125  *   GST_INFO ("Block until element is waiting for a clock notification\n");
126  *   gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
127  *   GST_INFO ("Advance to the requested time of the clock notification\n");
128  *   gst_test_clock_advance_time (test_clock, latency);
129  *   GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
130  *   processed_id = gst_test_clock_process_next_clock_id (test_clock);
131  *   g_assert (processed_id == pending_id);
132  *   g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
133  *   gst_clock_id_unref (pending_id);
134  *   gst_clock_id_unref (processed_id);
135  *
136  *   GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
137  *   g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
138  *   buf = get_buffer_pushed_by_element (element, ...);
139  *   g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==, latency);
140  *   gst_buffer_unref (buf);
141  *   GST_INFO ("Check that element does not wait for any clock notification\n");
142  *   g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
143  *
144  *   GST_INFO ("Set time, create and push the second buffer\n");
145  *   gst_test_clock_advance_time (test_clock, 10 * GST_SECOND);
146  *   buf = create_test_buffer (gst_clock_get_time (clock), ...);
147  *   gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);
148  *
149  *   GST_INFO ("Block until element is waiting for a new clock notification\n");
150  *   (gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
151  *   GST_INFO ("Advance past 7ms beyond the requested time of the clock notification\n");
152  *   gst_test_clock_advance_time (test_clock, latency + 7 * GST_MSECOND);
153  *   GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
154  *   processed_id = gst_test_clock_process_next_clock_id (test_clock);
155  *   g_assert (processed_id == pending_id);
156  *   g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
157  *   gst_clock_id_unref (pending_id);
158  *   gst_clock_id_unref (processed_id);
159  *
160  *   GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
161  *   g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
162  *   buf = get_buffer_pushed_by_element (element, ...);
163  *   g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==,
164  *       10 * GST_SECOND + latency + 7 * GST_MSECOND);
165  *   gst_buffer_unref (buf);
166  *   GST_INFO ("Check that element does not wait for any clock notification\n");
167  *   g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
168  *   ...
169  * ]|
170  *
171  * Since #GstTestClock is only supposed to be used in unit tests it calls
172  * g_assert(), g_assert_cmpint() or g_assert_cmpuint() to validate all function
173  * arguments. This will highlight any issues with the unit test code itself.
174  */
175
176 #ifdef HAVE_CONFIG_H
177 #include <config.h>
178 #endif
179
180 #include "gsttestclock.h"
181
182 enum
183 {
184   PROP_0,
185   PROP_START_TIME,
186   PROP_CLOCK_TYPE
187 };
188
189 typedef struct _GstClockEntryContext GstClockEntryContext;
190
191 struct _GstClockEntryContext
192 {
193   GstClockEntry *clock_entry;
194   GstClockTimeDiff time_diff;
195 };
196
197 struct _GstTestClockPrivate
198 {
199   GstClockType clock_type;
200   GstClockTime start_time;
201   GstClockTime internal_time;
202   GList *entry_contexts;
203   GCond entry_added_cond;
204   GCond entry_processed_cond;
205 };
206
207 #define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_MONOTONIC
208
209 #define GST_TEST_CLOCK_GET_PRIVATE(obj) ((GST_TEST_CLOCK_CAST (obj))->priv)
210
211 GST_DEBUG_CATEGORY_STATIC (test_clock_debug);
212 #define GST_CAT_TEST_CLOCK test_clock_debug
213
214 #define _do_init \
215 G_STMT_START { \
216   GST_DEBUG_CATEGORY_INIT (test_clock_debug, "GST_TEST_CLOCK", \
217       GST_DEBUG_BOLD, "Test clocks for unit tests"); \
218 } G_STMT_END
219
220 G_DEFINE_TYPE_WITH_CODE (GstTestClock, gst_test_clock,
221     GST_TYPE_CLOCK, _do_init);
222
223 static GstObjectClass *parent_class = NULL;
224
225 static void gst_test_clock_constructed (GObject * object);
226 static void gst_test_clock_dispose (GObject * object);
227 static void gst_test_clock_finalize (GObject * object);
228 static void gst_test_clock_get_property (GObject * object, guint property_id,
229     GValue * value, GParamSpec * pspec);
230 static void gst_test_clock_set_property (GObject * object, guint property_id,
231     const GValue * value, GParamSpec * pspec);
232
233 static GstClockTime gst_test_clock_get_resolution (GstClock * clock);
234 static GstClockTime gst_test_clock_get_internal_time (GstClock * clock);
235 static GstClockReturn gst_test_clock_wait (GstClock * clock,
236     GstClockEntry * entry, GstClockTimeDiff * jitter);
237 static GstClockReturn gst_test_clock_wait_async (GstClock * clock,
238     GstClockEntry * entry);
239 static void gst_test_clock_unschedule (GstClock * clock, GstClockEntry * entry);
240
241 static gboolean gst_test_clock_peek_next_pending_id_unlocked (GstTestClock *
242     test_clock, GstClockID * pending_id);
243 static guint gst_test_clock_peek_id_count_unlocked (GstTestClock * test_clock);
244
245 static void gst_test_clock_add_entry (GstTestClock * test_clock,
246     GstClockEntry * entry, GstClockTimeDiff * jitter);
247 static void gst_test_clock_remove_entry (GstTestClock * test_clock,
248     GstClockEntry * entry);
249 static GstClockEntryContext *gst_test_clock_lookup_entry_context (GstTestClock *
250     test_clock, GstClockEntry * clock_entry);
251
252 static gint gst_clock_entry_context_compare_func (gconstpointer a,
253     gconstpointer b);
254
255 static void
256 gst_test_clock_class_init (GstTestClockClass * klass)
257 {
258   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
259   GstClockClass *gstclock_class = GST_CLOCK_CLASS (klass);
260   GParamSpec *pspec;
261
262   parent_class = g_type_class_peek_parent (klass);
263
264   g_type_class_add_private (klass, sizeof (GstTestClockPrivate));
265
266   gobject_class->constructed = GST_DEBUG_FUNCPTR (gst_test_clock_constructed);
267   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_test_clock_dispose);
268   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_test_clock_finalize);
269   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_test_clock_get_property);
270   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_test_clock_set_property);
271
272   gstclock_class->get_resolution =
273       GST_DEBUG_FUNCPTR (gst_test_clock_get_resolution);
274   gstclock_class->get_internal_time =
275       GST_DEBUG_FUNCPTR (gst_test_clock_get_internal_time);
276   gstclock_class->wait = GST_DEBUG_FUNCPTR (gst_test_clock_wait);
277   gstclock_class->wait_async = GST_DEBUG_FUNCPTR (gst_test_clock_wait_async);
278   gstclock_class->unschedule = GST_DEBUG_FUNCPTR (gst_test_clock_unschedule);
279
280   /**
281    * GstTestClock:start-time:
282    *
283    * When a #GstTestClock is constructed it will have a certain start time set.
284    * If the clock was created using gst_test_clock_new_with_start_time() then
285    * this property contains the value of the @start_time argument. If
286    * gst_test_clock_new() was called the clock started at time zero, and thus
287    * this property contains the value 0.
288    */
289   pspec = g_param_spec_uint64 ("start-time", "Start Time",
290       "Start Time of the Clock", 0, G_MAXUINT64, 0,
291       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
292   g_object_class_install_property (gobject_class, PROP_START_TIME, pspec);
293
294   g_object_class_install_property (gobject_class, PROP_CLOCK_TYPE,
295       g_param_spec_enum ("clock-type", "Clock type",
296           "The kind of clock implementation to be reported by this clock",
297           GST_TYPE_CLOCK_TYPE, DEFAULT_CLOCK_TYPE,
298           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
299
300 }
301
302 static void
303 gst_test_clock_init (GstTestClock * test_clock)
304 {
305   GstTestClockPrivate *priv;
306
307   test_clock->priv = G_TYPE_INSTANCE_GET_PRIVATE (test_clock,
308       GST_TYPE_TEST_CLOCK, GstTestClockPrivate);
309
310   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
311
312   g_cond_init (&priv->entry_added_cond);
313   g_cond_init (&priv->entry_processed_cond);
314   priv->clock_type = DEFAULT_CLOCK_TYPE;
315
316   GST_OBJECT_FLAG_SET (test_clock,
317       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
318       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
319       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
320       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
321 }
322
323 static void
324 gst_test_clock_constructed (GObject * object)
325 {
326   GstTestClock *test_clock = GST_TEST_CLOCK (object);
327   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
328
329   priv->internal_time = priv->start_time;
330
331   G_OBJECT_CLASS (parent_class)->constructed (object);
332 }
333
334 static void
335 gst_test_clock_dispose (GObject * object)
336 {
337   GstTestClock *test_clock = GST_TEST_CLOCK (object);
338   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
339
340   GST_OBJECT_LOCK (test_clock);
341
342   while (priv->entry_contexts != NULL) {
343     GstClockEntryContext *ctx = priv->entry_contexts->data;
344     gst_test_clock_remove_entry (test_clock, ctx->clock_entry);
345   }
346
347   GST_OBJECT_UNLOCK (test_clock);
348
349   G_OBJECT_CLASS (parent_class)->dispose (object);
350 }
351
352 static void
353 gst_test_clock_finalize (GObject * object)
354 {
355   GstTestClock *test_clock = GST_TEST_CLOCK (object);
356   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
357
358   g_cond_clear (&priv->entry_added_cond);
359   g_cond_clear (&priv->entry_processed_cond);
360
361   G_OBJECT_CLASS (parent_class)->finalize (object);
362 }
363
364 static void
365 gst_test_clock_get_property (GObject * object, guint property_id,
366     GValue * value, GParamSpec * pspec)
367 {
368   GstTestClock *test_clock = GST_TEST_CLOCK (object);
369   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
370
371   switch (property_id) {
372     case PROP_START_TIME:
373       g_value_set_uint64 (value, priv->start_time);
374       break;
375     case PROP_CLOCK_TYPE:
376       g_value_set_enum (value, priv->clock_type);
377       break;
378     default:
379       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
380       break;
381   }
382 }
383
384 static void
385 gst_test_clock_set_property (GObject * object, guint property_id,
386     const GValue * value, GParamSpec * pspec)
387 {
388   GstTestClock *test_clock = GST_TEST_CLOCK (object);
389   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
390
391   switch (property_id) {
392     case PROP_START_TIME:
393       priv->start_time = g_value_get_uint64 (value);
394       GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
395           "test clock start time initialized at %" GST_TIME_FORMAT,
396           GST_TIME_ARGS (priv->start_time));
397       break;
398     case PROP_CLOCK_TYPE:
399       priv->clock_type = (GstClockType) g_value_get_enum (value);
400       GST_CAT_DEBUG (GST_CAT_TEST_CLOCK, "clock-type set to %d",
401           priv->clock_type);
402       break;
403     default:
404       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
405       break;
406   }
407 }
408
409 static GstClockTime
410 gst_test_clock_get_resolution (GstClock * clock)
411 {
412   (void) clock;
413   return 1;
414 }
415
416 static GstClockTime
417 gst_test_clock_get_internal_time (GstClock * clock)
418 {
419   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
420   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
421   GstClockTime result;
422
423   GST_OBJECT_LOCK (test_clock);
424
425   GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
426       "retrieving test clock time %" GST_TIME_FORMAT,
427       GST_TIME_ARGS (priv->internal_time));
428   result = priv->internal_time;
429
430   GST_OBJECT_UNLOCK (test_clock);
431
432   return result;
433 }
434
435 static GstClockReturn
436 gst_test_clock_wait (GstClock * clock,
437     GstClockEntry * entry, GstClockTimeDiff * jitter)
438 {
439   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
440   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
441
442   GST_OBJECT_LOCK (test_clock);
443
444   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
445       "requesting synchronous clock notification at %" GST_TIME_FORMAT,
446       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
447
448   if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)
449     goto was_unscheduled;
450
451   if (gst_test_clock_lookup_entry_context (test_clock, entry) == NULL)
452     gst_test_clock_add_entry (test_clock, entry, jitter);
453
454   GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_BUSY;
455
456   while (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_BUSY)
457     g_cond_wait (&priv->entry_processed_cond, GST_OBJECT_GET_LOCK (test_clock));
458
459   GST_OBJECT_UNLOCK (test_clock);
460
461   return GST_CLOCK_ENTRY_STATUS (entry);
462
463   /* ERRORS */
464 was_unscheduled:
465   {
466     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
467         "entry was unscheduled");
468     GST_OBJECT_UNLOCK (test_clock);
469     return GST_CLOCK_UNSCHEDULED;
470   }
471 }
472
473 static GstClockReturn
474 gst_test_clock_wait_async (GstClock * clock, GstClockEntry * entry)
475 {
476   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
477
478   GST_OBJECT_LOCK (test_clock);
479
480   if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)
481     goto was_unscheduled;
482
483   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
484       "requesting asynchronous clock notification at %" GST_TIME_FORMAT,
485       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
486
487   gst_test_clock_add_entry (test_clock, entry, NULL);
488
489   GST_OBJECT_UNLOCK (test_clock);
490
491   return GST_CLOCK_OK;
492
493   /* ERRORS */
494 was_unscheduled:
495   {
496     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
497         "entry was unscheduled");
498     GST_OBJECT_UNLOCK (test_clock);
499     return GST_CLOCK_UNSCHEDULED;
500   }
501 }
502
503 static void
504 gst_test_clock_unschedule (GstClock * clock, GstClockEntry * entry)
505 {
506   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
507
508   GST_OBJECT_LOCK (test_clock);
509
510   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
511       "unscheduling requested clock notification at %" GST_TIME_FORMAT,
512       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
513
514   GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_UNSCHEDULED;
515   gst_test_clock_remove_entry (test_clock, entry);
516
517   GST_OBJECT_UNLOCK (test_clock);
518 }
519
520 static gboolean
521 gst_test_clock_peek_next_pending_id_unlocked (GstTestClock * test_clock,
522     GstClockID * pending_id)
523 {
524   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
525   GList *imminent_clock_id = g_list_first (priv->entry_contexts);
526   gboolean result = FALSE;
527
528   if (imminent_clock_id != NULL) {
529     GstClockEntryContext *ctx = imminent_clock_id->data;
530
531     if (pending_id != NULL) {
532       *pending_id = gst_clock_id_ref (ctx->clock_entry);
533     }
534
535     result = TRUE;
536   }
537
538   return result;
539 }
540
541 static guint
542 gst_test_clock_peek_id_count_unlocked (GstTestClock * test_clock)
543 {
544   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
545
546   return g_list_length (priv->entry_contexts);
547 }
548
549 static void
550 gst_test_clock_add_entry (GstTestClock * test_clock,
551     GstClockEntry * entry, GstClockTimeDiff * jitter)
552 {
553   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
554   GstClockTime now;
555   GstClockEntryContext *ctx;
556
557   now = gst_clock_adjust_unlocked (GST_CLOCK (test_clock), priv->internal_time);
558
559   if (jitter != NULL)
560     *jitter = GST_CLOCK_DIFF (GST_CLOCK_ENTRY_TIME (entry), now);
561
562   ctx = g_slice_new (GstClockEntryContext);
563   ctx->clock_entry = GST_CLOCK_ENTRY (gst_clock_id_ref (entry));
564   ctx->time_diff = GST_CLOCK_DIFF (now, GST_CLOCK_ENTRY_TIME (entry));
565
566   priv->entry_contexts = g_list_insert_sorted (priv->entry_contexts, ctx,
567       gst_clock_entry_context_compare_func);
568
569   g_cond_broadcast (&priv->entry_added_cond);
570 }
571
572 static void
573 gst_test_clock_remove_entry (GstTestClock * test_clock, GstClockEntry * entry)
574 {
575   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
576   GstClockEntryContext *ctx;
577
578   ctx = gst_test_clock_lookup_entry_context (test_clock, entry);
579   if (ctx != NULL) {
580     gst_clock_id_unref (ctx->clock_entry);
581     priv->entry_contexts = g_list_remove (priv->entry_contexts, ctx);
582     g_slice_free (GstClockEntryContext, ctx);
583
584     g_cond_broadcast (&priv->entry_processed_cond);
585   }
586 }
587
588 static GstClockEntryContext *
589 gst_test_clock_lookup_entry_context (GstTestClock * test_clock,
590     GstClockEntry * clock_entry)
591 {
592   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
593   GstClockEntryContext *result = NULL;
594   GList *cur;
595
596   for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
597     GstClockEntryContext *ctx = cur->data;
598
599     if (ctx->clock_entry == clock_entry) {
600       result = ctx;
601       break;
602     }
603   }
604
605   return result;
606 }
607
608 static gint
609 gst_clock_entry_context_compare_func (gconstpointer a, gconstpointer b)
610 {
611   const GstClockEntryContext *ctx_a = a;
612   const GstClockEntryContext *ctx_b = b;
613
614   return gst_clock_id_compare_func (ctx_a->clock_entry, ctx_b->clock_entry);
615 }
616
617 static void
618 process_entry_context_unlocked (GstTestClock * test_clock,
619     GstClockEntryContext * ctx)
620 {
621   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
622   GstClockEntry *entry = ctx->clock_entry;
623
624   if (ctx->time_diff >= 0)
625     GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK;
626   else
627     GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_EARLY;
628
629   if (entry->func != NULL) {
630     GST_OBJECT_UNLOCK (test_clock);
631     entry->func (GST_CLOCK (test_clock), priv->internal_time, entry,
632         entry->user_data);
633     GST_OBJECT_LOCK (test_clock);
634   }
635
636   gst_test_clock_remove_entry (test_clock, entry);
637
638   if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_PERIODIC) {
639     GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry);
640
641     if (entry->func != NULL)
642       gst_test_clock_add_entry (test_clock, entry, NULL);
643   }
644 }
645
646 static GList *
647 gst_test_clock_get_pending_id_list_unlocked (GstTestClock * test_clock)
648 {
649   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
650   GQueue queue = G_QUEUE_INIT;
651   GList *cur;
652
653   for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
654     GstClockEntryContext *ctx = cur->data;
655
656     g_queue_push_tail (&queue, gst_clock_id_ref (ctx->clock_entry));
657   }
658
659   return queue.head;
660 }
661
662 /**
663  * gst_test_clock_new:
664  *
665  * Creates a new test clock with its time set to zero.
666  *
667  * MT safe.
668  *
669  * Returns: (transfer full): a #GstTestClock cast to #GstClock.
670  *
671  * Since: 1.2
672  */
673 GstClock *
674 gst_test_clock_new (void)
675 {
676   return gst_test_clock_new_with_start_time (0);
677 }
678
679 /**
680  * gst_test_clock_new_with_start_time:
681  * @start_time: a #GstClockTime set to the desired start time of the clock.
682  *
683  * Creates a new test clock with its time set to the specified time.
684  *
685  * MT safe.
686  *
687  * Returns: (transfer full): a #GstTestClock cast to #GstClock.
688  *
689  * Since: 1.2
690  */
691 GstClock *
692 gst_test_clock_new_with_start_time (GstClockTime start_time)
693 {
694   g_assert_cmpuint (start_time, !=, GST_CLOCK_TIME_NONE);
695   return g_object_new (GST_TYPE_TEST_CLOCK, "start-time", start_time, NULL);
696 }
697
698 /**
699  * gst_test_clock_set_time:
700  * @test_clock: a #GstTestClock of which to set the time
701  * @new_time: a #GstClockTime later than that returned by gst_clock_get_time()
702  *
703  * Sets the time of @test_clock to the time given by @new_time. The time of
704  * @test_clock is monotonically increasing, therefore providing a @new_time
705  * which is earlier or equal to the time of the clock as given by
706  * gst_clock_get_time() is a programming error.
707  *
708  * MT safe.
709  *
710  * Since: 1.2
711  */
712 void
713 gst_test_clock_set_time (GstTestClock * test_clock, GstClockTime new_time)
714 {
715   GstTestClockPrivate *priv;
716
717   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
718
719   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
720
721   g_assert_cmpuint (new_time, !=, GST_CLOCK_TIME_NONE);
722
723   GST_OBJECT_LOCK (test_clock);
724
725   g_assert_cmpuint (new_time, >=, priv->internal_time);
726
727   priv->internal_time = new_time;
728   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
729       "clock set to %" GST_TIME_FORMAT, GST_TIME_ARGS (new_time));
730
731   GST_OBJECT_UNLOCK (test_clock);
732 }
733
734 /**
735  * gst_test_clock_advance_time:
736  * @test_clock: a #GstTestClock for which to increase the time
737  * @delta: a positive #GstClockTimeDiff to be added to the time of the clock
738  *
739  * Advances the time of the @test_clock by the amount given by @delta. The
740  * time of @test_clock is monotonically increasing, therefore providing a
741  * @delta which is negative or zero is a programming error.
742  *
743  * MT safe.
744  *
745  * Since: 1.2
746  */
747 void
748 gst_test_clock_advance_time (GstTestClock * test_clock, GstClockTimeDiff delta)
749 {
750   GstTestClockPrivate *priv;
751
752   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
753
754   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
755
756   g_assert_cmpint (delta, >=, 0);
757   g_assert_cmpuint (delta, <, G_MAXUINT64 - delta);
758
759   GST_OBJECT_LOCK (test_clock);
760
761   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
762       "advancing clock by %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
763       GST_TIME_ARGS (delta), GST_TIME_ARGS (priv->internal_time + delta));
764   priv->internal_time += delta;
765
766   GST_OBJECT_UNLOCK (test_clock);
767 }
768
769 /**
770  * gst_test_clock_peek_id_count:
771  * @test_clock: a #GstTestClock for which to count notifications
772  *
773  * Determine the number of pending clock notifications that have been
774  * requested from the @test_clock.
775  *
776  * MT safe.
777  *
778  * Returns: the number of pending clock notifications.
779  *
780  * Since: 1.2
781  */
782 guint
783 gst_test_clock_peek_id_count (GstTestClock * test_clock)
784 {
785   guint result;
786
787   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
788
789   GST_OBJECT_LOCK (test_clock);
790   result = gst_test_clock_peek_id_count_unlocked (test_clock);
791   GST_OBJECT_UNLOCK (test_clock);
792
793   return result;
794 }
795
796 /**
797  * gst_test_clock_has_id:
798  * @test_clock: a #GstTestClock to ask if it provided the notification
799  * @id: (transfer none): a #GstClockID clock notification
800  *
801  * Checks whether @test_clock was requested to provide the clock notification
802  * given by @id.
803  *
804  * MT safe.
805  *
806  * Returns: %TRUE if the clock has been asked to provide the given clock
807  * notification, %FALSE otherwise.
808  *
809  * Since: 1.2
810  */
811 gboolean
812 gst_test_clock_has_id (GstTestClock * test_clock, GstClockID id)
813 {
814   gboolean result;
815
816   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
817   g_assert (id != NULL);
818
819   GST_OBJECT_LOCK (test_clock);
820   result = gst_test_clock_lookup_entry_context (test_clock, id) != NULL;
821   GST_OBJECT_UNLOCK (test_clock);
822
823   return result;
824 }
825
826 /**
827  * gst_test_clock_peek_next_pending_id:
828  * @test_clock: a #GstTestClock to check the clock notifications for
829  * @pending_id: (allow-none) (out) (transfer full): a #GstClockID clock
830  * notification to look for
831  *
832  * Determines if the @pending_id is the next clock notification scheduled to
833  * be triggered given the current time of the @test_clock.
834  *
835  * MT safe.
836  *
837  * Return: %TRUE if @pending_id is the next clock notification to be
838  * triggered, %FALSE otherwise.
839  *
840  * Since: 1.2
841  */
842 gboolean
843 gst_test_clock_peek_next_pending_id (GstTestClock * test_clock,
844     GstClockID * pending_id)
845 {
846   gboolean result;
847
848   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
849
850   GST_OBJECT_LOCK (test_clock);
851   result = gst_test_clock_peek_next_pending_id_unlocked (test_clock,
852       pending_id);
853   GST_OBJECT_UNLOCK (test_clock);
854
855   return result;
856 }
857
858 /**
859  * gst_test_clock_wait_for_next_pending_id:
860  * @test_clock: #GstTestClock for which to get the pending clock notification
861  * @pending_id: (allow-none) (out) (transfer full): #GstClockID
862  * with information about the pending clock notification
863  *
864  * Waits until a clock notification is requested from @test_clock. There is no
865  * timeout for this wait, see the main description of #GstTestClock. A reference
866  * to the pending clock notification is stored in @pending_id.
867  *
868  * MT safe.
869  *
870  * Since: 1.2
871  */
872 void
873 gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock,
874     GstClockID * pending_id)
875 {
876   GstTestClockPrivate *priv;
877
878   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
879
880   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
881
882   GST_OBJECT_LOCK (test_clock);
883
884   while (priv->entry_contexts == NULL)
885     g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock));
886
887   if (!gst_test_clock_peek_next_pending_id_unlocked (test_clock, pending_id))
888     g_assert_not_reached ();
889
890   GST_OBJECT_UNLOCK (test_clock);
891 }
892
893 /**
894  * gst_test_clock_wait_for_pending_id_count:
895  * @test_clock: #GstTestClock for which to await having enough pending clock
896  * @count: the number of pending clock notifications to wait for
897  *
898  * Blocks until at least @count clock notifications have been requested from
899  * @test_clock. There is no timeout for this wait, see the main description of
900  * #GstTestClock.
901  *
902  * Since: 1.2
903  *
904  * Deprecated: use gst_test_clock_wait_for_multiple_pending_ids() instead.
905  */
906 #ifndef GST_REMOVE_DEPRECATED
907 #ifdef GST_DISABLE_DEPRECATED
908 void gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock,
909     guint count);
910 #endif
911 void
912 gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock,
913     guint count)
914 {
915   gst_test_clock_wait_for_multiple_pending_ids (test_clock, count, NULL);
916 }
917 #endif
918
919 /**
920  * gst_test_clock_process_next_clock_id:
921  * @test_clock: a #GstTestClock for which to retrieve the next pending clock
922  * notification
923  *
924  * MT safe.
925  *
926  * Returns: (transfer full): a #GstClockID containing the next pending clock
927  * notification.
928  *
929  * Since: 1.2
930  */
931 GstClockID
932 gst_test_clock_process_next_clock_id (GstTestClock * test_clock)
933 {
934   GstTestClockPrivate *priv;
935   GstClockID result = NULL;
936   GstClockEntryContext *ctx = NULL;
937   GList *cur;
938
939   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), NULL);
940
941   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
942
943   GST_OBJECT_LOCK (test_clock);
944
945   for (cur = priv->entry_contexts; cur != NULL && result == NULL;
946       cur = cur->next) {
947     ctx = cur->data;
948
949     if (priv->internal_time >= GST_CLOCK_ENTRY_TIME (ctx->clock_entry))
950       result = gst_clock_id_ref (ctx->clock_entry);
951   }
952
953   if (result != NULL)
954     process_entry_context_unlocked (test_clock, ctx);
955
956   GST_OBJECT_UNLOCK (test_clock);
957
958   return result;
959 }
960
961 /**
962  * gst_test_clock_get_next_entry_time:
963  * @test_clock: a #GstTestClock to fetch the next clock notification time for
964  *
965  * Retrieve the requested time for the next pending clock notification.
966  *
967  * MT safe.
968  *
969  * Returns: a #GstClockTime set to the time of the next pending clock
970  * notification. If no clock notifications have been requested
971  * %GST_CLOCK_TIME_NONE will be returned.
972  *
973  * Since: 1.2
974  */
975 GstClockTime
976 gst_test_clock_get_next_entry_time (GstTestClock * test_clock)
977 {
978   GstTestClockPrivate *priv;
979   GstClockTime result = GST_CLOCK_TIME_NONE;
980   GList *imminent_clock_id;
981
982   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), GST_CLOCK_TIME_NONE);
983
984   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
985
986   GST_OBJECT_LOCK (test_clock);
987
988   /* The list of pending clock notifications is sorted by time,
989      so the most imminent one is the first one in the list. */
990   imminent_clock_id = g_list_first (priv->entry_contexts);
991   if (imminent_clock_id != NULL) {
992     GstClockEntryContext *ctx = imminent_clock_id->data;
993     result = GST_CLOCK_ENTRY_TIME (ctx->clock_entry);
994   }
995
996   GST_OBJECT_UNLOCK (test_clock);
997
998   return result;
999 }
1000
1001 /**
1002  * gst_test_clock_wait_for_multiple_pending_ids:
1003  * @test_clock: #GstTestClock for which to await having enough pending clock
1004  * @count: the number of pending clock notifications to wait for
1005  * @pending_list: (out) (element-type Gst.ClockID) (transfer full) (allow-none): Address
1006  *     of a #GList pointer variable to store the list of pending #GstClockIDs
1007  *     that expired, or %NULL
1008  *
1009  * Blocks until at least @count clock notifications have been requested from
1010  * @test_clock. There is no timeout for this wait, see the main description of
1011  * #GstTestClock.
1012  *
1013  * MT safe.
1014  *
1015  * Since: 1.4
1016  */
1017 void
1018 gst_test_clock_wait_for_multiple_pending_ids (GstTestClock * test_clock,
1019     guint count, GList ** pending_list)
1020 {
1021   GstTestClockPrivate *priv;
1022
1023   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
1024   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
1025
1026   GST_OBJECT_LOCK (test_clock);
1027
1028   while (g_list_length (priv->entry_contexts) < count)
1029     g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock));
1030
1031   if (pending_list)
1032     *pending_list = gst_test_clock_get_pending_id_list_unlocked (test_clock);
1033
1034   GST_OBJECT_UNLOCK (test_clock);
1035 }
1036
1037 /**
1038  * gst_test_clock_process_id_list:
1039  * @test_clock: #GstTestClock for which to process the pending IDs
1040  * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List
1041  *     of pending #GstClockIDs
1042  *
1043  * Processes and releases the pending IDs in the list.
1044  *
1045  * MT safe.
1046  *
1047  * Since: 1.4
1048  */
1049 guint
1050 gst_test_clock_process_id_list (GstTestClock * test_clock,
1051     const GList * pending_list)
1052 {
1053   const GList *cur;
1054   guint result = 0;
1055
1056   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
1057
1058   GST_OBJECT_LOCK (test_clock);
1059
1060   for (cur = pending_list; cur != NULL; cur = cur->next) {
1061     GstClockID pending_id = cur->data;
1062     GstClockEntryContext *ctx =
1063         gst_test_clock_lookup_entry_context (test_clock, pending_id);
1064     if (ctx) {
1065       process_entry_context_unlocked (test_clock, ctx);
1066       result++;
1067     }
1068   }
1069   GST_OBJECT_UNLOCK (test_clock);
1070
1071   return result;
1072 }
1073
1074 /**
1075  * gst_test_clock_id_list_get_latest_time:
1076  * @pending_list:  (element-type Gst.ClockID) (transfer none) (allow-none): List
1077  *     of of pending #GstClockIDs
1078  *
1079  * Finds the latest time inside the list.
1080  *
1081  * MT safe.
1082  *
1083  * Since: 1.4
1084  */
1085 GstClockTime
1086 gst_test_clock_id_list_get_latest_time (const GList * pending_list)
1087 {
1088   const GList *cur;
1089   GstClockTime result = 0;
1090
1091   for (cur = pending_list; cur != NULL; cur = cur->next) {
1092     GstClockID *pending_id = cur->data;
1093     GstClockTime time = gst_clock_id_get_time (pending_id);
1094     if (time > result)
1095       result = time;
1096   }
1097
1098   return result;
1099 }
1100
1101 /**
1102  * gst_test_clock_crank:
1103  * @test_clock: #GstTestClock to crank
1104  *
1105  * A "crank" consists of three steps:
1106  * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
1107  * 2: Advance the #GstTestClock to the time the #GstClockID is waiting for.
1108  * 3: Release the #GstClockID wait.
1109  * A "crank" can be though of as the notion of
1110  * manually driving the clock forward to its next logical step.
1111  *
1112  * Return: %TRUE if the crank was successful, %FALSE otherwise.
1113  *
1114  * MT safe.
1115  *
1116  * Since: 1.8
1117  */
1118 gboolean
1119 gst_test_clock_crank (GstTestClock * test_clock)
1120 {
1121   GstClockID res, pending;
1122   gboolean result;
1123
1124   gst_test_clock_wait_for_next_pending_id (test_clock, &pending);
1125   gst_test_clock_set_time (test_clock, gst_clock_id_get_time (pending));
1126   res = gst_test_clock_process_next_clock_id (test_clock);
1127   if (G_LIKELY (res == pending)) {
1128     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
1129         "cranked to time %" GST_TIME_FORMAT,
1130         GST_TIME_ARGS (gst_clock_get_time (GST_CLOCK (test_clock))));
1131     result = TRUE;
1132   } else {
1133     GST_CAT_WARNING_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
1134         "testclock next id != pending (%p != %p)", res, pending);
1135     result = FALSE;
1136   }
1137
1138   if (G_LIKELY (res != NULL))
1139     gst_clock_id_unref (res);
1140
1141   gst_clock_id_unref (pending);
1142
1143   return result;
1144 }