introspection: Assorted minor introspection and documentation fixes
[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  * @short_description: Controllable, deterministic clock for GStreamer unit tests
27  * @see_also: #GstSystemClock, #GstClock
28  *
29  * GstTestClock is an implementation of #GstClock which has different
30  * behaviour compared to #GstSystemClock. Time for #GstSystemClock advances
31  * according to the system time, while time for #GstTestClock changes only
32  * when gst_test_clock_set_time() or gst_test_clock_advance_time() are
33  * called. #GstTestClock provides unit tests with the possibility to
34  * precisely advance the time in a deterministic manner, independent of the
35  * system time or any other external factors.
36  *
37  * <example>
38  * <title>Advancing the time of a #GstTestClock</title>
39  *   <programlisting language="c">
40  *   #include &lt;gst/gst.h&gt;
41  *   #include &lt;gst/check/gsttestclock.h&gt;
42  *
43  *   GstClock *clock;
44  *   GstTestClock *test_clock;
45  *
46  *   clock = gst_test_clock_new ();
47  *   test_clock = GST_TEST_CLOCK (clock);
48  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
49  *   gst_test_clock_advance_time ( test_clock, 1 * GST_SECOND);
50  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
51  *   g_usleep (10 * G_USEC_PER_SEC);
52  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
53  *   gst_test_clock_set_time (test_clock, 42 * GST_SECOND);
54  *   GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
55  *   ...
56  *   </programlisting>
57  * </example>
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  * <example>
97  * <title>Demonstration of how to work with clock notifications and #GstTestClock</title>
98  *   <programlisting language="c">
99  *   #include &lt;gst/gst.h&gt;
100  *   #include &lt;gst/check/gstcheck.h&gt;
101  *   #include &lt;gst/check/gsttestclock.h&gt;
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) == FALSE);
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) == FALSE);
168  *   ...
169  *   </programlisting>
170  * </example>
171  *
172  * Since #GstTestClock is only supposed to be used in unit tests it calls
173  * g_assert(), g_assert_cmpint() or g_assert_cmpuint() to validate all function
174  * arguments. This will highlight any issues with the unit test code itself.
175  */
176
177 #ifdef HAVE_CONFIG_H
178 #include <config.h>
179 #endif
180
181 #include "gsttestclock.h"
182
183 enum
184 {
185   PROP_0,
186   PROP_START_TIME
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   GstClockTime start_time;
200   GstClockTime internal_time;
201   GList *entry_contexts;
202   GCond entry_added_cond;
203   GCond entry_processed_cond;
204 };
205
206 #define GST_TEST_CLOCK_GET_PRIVATE(obj) ((GST_TEST_CLOCK_CAST (obj))->priv)
207
208 GST_DEBUG_CATEGORY_STATIC (test_clock_debug);
209 #define GST_CAT_TEST_CLOCK test_clock_debug
210
211 #define _do_init \
212 G_STMT_START { \
213   GST_DEBUG_CATEGORY_INIT (test_clock_debug, "GST_TEST_CLOCK", \
214       GST_DEBUG_BOLD, "Test clocks for unit tests"); \
215 } G_STMT_END
216
217 G_DEFINE_TYPE_WITH_CODE (GstTestClock, gst_test_clock,
218     GST_TYPE_CLOCK, _do_init);
219
220 static GstObjectClass *parent_class = NULL;
221
222 static void gst_test_clock_constructed (GObject * object);
223 static void gst_test_clock_dispose (GObject * object);
224 static void gst_test_clock_finalize (GObject * object);
225 static void gst_test_clock_get_property (GObject * object, guint property_id,
226     GValue * value, GParamSpec * pspec);
227 static void gst_test_clock_set_property (GObject * object, guint property_id,
228     const GValue * value, GParamSpec * pspec);
229
230 static GstClockTime gst_test_clock_get_resolution (GstClock * clock);
231 static GstClockTime gst_test_clock_get_internal_time (GstClock * clock);
232 static GstClockReturn gst_test_clock_wait (GstClock * clock,
233     GstClockEntry * entry, GstClockTimeDiff * jitter);
234 static GstClockReturn gst_test_clock_wait_async (GstClock * clock,
235     GstClockEntry * entry);
236 static void gst_test_clock_unschedule (GstClock * clock, GstClockEntry * entry);
237
238 static gboolean gst_test_clock_peek_next_pending_id_unlocked (GstTestClock *
239     test_clock, GstClockID * pending_id);
240 static guint gst_test_clock_peek_id_count_unlocked (GstTestClock * test_clock);
241
242 static void gst_test_clock_add_entry (GstTestClock * test_clock,
243     GstClockEntry * entry, GstClockTimeDiff * jitter);
244 static void gst_test_clock_remove_entry (GstTestClock * test_clock,
245     GstClockEntry * entry);
246 static GstClockEntryContext *gst_test_clock_lookup_entry_context (GstTestClock *
247     test_clock, GstClockEntry * clock_entry);
248
249 static gint gst_clock_entry_context_compare_func (gconstpointer a,
250     gconstpointer b);
251
252 static void
253 gst_test_clock_class_init (GstTestClockClass * klass)
254 {
255   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
256   GstClockClass *gstclock_class = GST_CLOCK_CLASS (klass);
257   GParamSpec *pspec;
258
259   parent_class = g_type_class_peek_parent (klass);
260
261   g_type_class_add_private (klass, sizeof (GstTestClockPrivate));
262
263   gobject_class->constructed = GST_DEBUG_FUNCPTR (gst_test_clock_constructed);
264   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_test_clock_dispose);
265   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_test_clock_finalize);
266   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_test_clock_get_property);
267   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_test_clock_set_property);
268
269   gstclock_class->get_resolution =
270       GST_DEBUG_FUNCPTR (gst_test_clock_get_resolution);
271   gstclock_class->get_internal_time =
272       GST_DEBUG_FUNCPTR (gst_test_clock_get_internal_time);
273   gstclock_class->wait = GST_DEBUG_FUNCPTR (gst_test_clock_wait);
274   gstclock_class->wait_async = GST_DEBUG_FUNCPTR (gst_test_clock_wait_async);
275   gstclock_class->unschedule = GST_DEBUG_FUNCPTR (gst_test_clock_unschedule);
276
277   /**
278    * GstTestClock:start-time:
279    *
280    * When a #GstTestClock is constructed it will have a certain start time set.
281    * If the clock was created using gst_test_clock_new_with_start_time() then
282    * this property contains the value of the @start_time argument. If
283    * gst_test_clock_new() was called the clock started at time zero, and thus
284    * this property contains the value 0.
285    */
286   pspec = g_param_spec_uint64 ("start-time", "Start Time",
287       "Start Time of the Clock", 0, G_MAXUINT64, 0,
288       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
289   g_object_class_install_property (gobject_class, PROP_START_TIME, pspec);
290 }
291
292 static void
293 gst_test_clock_init (GstTestClock * test_clock)
294 {
295   GstTestClockPrivate *priv;
296
297   test_clock->priv = G_TYPE_INSTANCE_GET_PRIVATE (test_clock,
298       GST_TYPE_TEST_CLOCK, GstTestClockPrivate);
299
300   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
301
302   g_cond_init (&priv->entry_added_cond);
303   g_cond_init (&priv->entry_processed_cond);
304
305   GST_OBJECT_FLAG_SET (test_clock,
306       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
307       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
308       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
309       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
310 }
311
312 static void
313 gst_test_clock_constructed (GObject * object)
314 {
315   GstTestClock *test_clock = GST_TEST_CLOCK (object);
316   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
317
318   priv->internal_time = priv->start_time;
319
320   G_OBJECT_CLASS (parent_class)->constructed (object);
321 }
322
323 static void
324 gst_test_clock_dispose (GObject * object)
325 {
326   GstTestClock *test_clock = GST_TEST_CLOCK (object);
327   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
328
329   GST_OBJECT_LOCK (test_clock);
330
331   while (priv->entry_contexts != NULL) {
332     GstClockEntryContext *ctx = priv->entry_contexts->data;
333     gst_test_clock_remove_entry (test_clock, ctx->clock_entry);
334   }
335
336   GST_OBJECT_UNLOCK (test_clock);
337
338   G_OBJECT_CLASS (parent_class)->dispose (object);
339 }
340
341 static void
342 gst_test_clock_finalize (GObject * object)
343 {
344   GstTestClock *test_clock = GST_TEST_CLOCK (object);
345   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
346
347   g_cond_clear (&priv->entry_added_cond);
348   g_cond_clear (&priv->entry_processed_cond);
349
350   G_OBJECT_CLASS (parent_class)->finalize (object);
351 }
352
353 static void
354 gst_test_clock_get_property (GObject * object, guint property_id,
355     GValue * value, GParamSpec * pspec)
356 {
357   GstTestClock *test_clock = GST_TEST_CLOCK (object);
358   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
359
360   switch (property_id) {
361     case PROP_START_TIME:
362       g_value_set_uint64 (value, priv->start_time);
363       break;
364     default:
365       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
366       break;
367   }
368 }
369
370 static void
371 gst_test_clock_set_property (GObject * object, guint property_id,
372     const GValue * value, GParamSpec * pspec)
373 {
374   GstTestClock *test_clock = GST_TEST_CLOCK (object);
375   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
376
377   switch (property_id) {
378     case PROP_START_TIME:
379       priv->start_time = g_value_get_uint64 (value);
380       GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
381           "test clock start time initialized at %" GST_TIME_FORMAT,
382           GST_TIME_ARGS (priv->start_time));
383       break;
384     default:
385       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
386       break;
387   }
388 }
389
390 static GstClockTime
391 gst_test_clock_get_resolution (GstClock * clock)
392 {
393   (void) clock;
394   return 1;
395 }
396
397 static GstClockTime
398 gst_test_clock_get_internal_time (GstClock * clock)
399 {
400   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
401   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
402   GstClockTime result;
403
404   GST_OBJECT_LOCK (test_clock);
405
406   GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
407       "retrieving test clock time %" GST_TIME_FORMAT,
408       GST_TIME_ARGS (priv->internal_time));
409   result = priv->internal_time;
410
411   GST_OBJECT_UNLOCK (test_clock);
412
413   return result;
414 }
415
416 static GstClockReturn
417 gst_test_clock_wait (GstClock * clock,
418     GstClockEntry * entry, GstClockTimeDiff * jitter)
419 {
420   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
421   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
422
423   GST_OBJECT_LOCK (test_clock);
424
425   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
426       "requesting synchronous clock notification at %" GST_TIME_FORMAT,
427       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
428
429   if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)
430     goto was_unscheduled;
431
432   if (gst_test_clock_lookup_entry_context (test_clock, entry) == NULL)
433     gst_test_clock_add_entry (test_clock, entry, jitter);
434
435   GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_BUSY;
436
437   while (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_BUSY)
438     g_cond_wait (&priv->entry_processed_cond, GST_OBJECT_GET_LOCK (test_clock));
439
440   GST_OBJECT_UNLOCK (test_clock);
441
442   return GST_CLOCK_ENTRY_STATUS (entry);
443
444   /* ERRORS */
445 was_unscheduled:
446   {
447     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
448         "entry was unscheduled");
449     GST_OBJECT_UNLOCK (test_clock);
450     return GST_CLOCK_UNSCHEDULED;
451   }
452 }
453
454 static GstClockReturn
455 gst_test_clock_wait_async (GstClock * clock, GstClockEntry * entry)
456 {
457   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
458
459   GST_OBJECT_LOCK (test_clock);
460
461   if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)
462     goto was_unscheduled;
463
464   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
465       "requesting asynchronous clock notification at %" GST_TIME_FORMAT,
466       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
467
468   gst_test_clock_add_entry (test_clock, entry, NULL);
469
470   GST_OBJECT_UNLOCK (test_clock);
471
472   return GST_CLOCK_OK;
473
474   /* ERRORS */
475 was_unscheduled:
476   {
477     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
478         "entry was unscheduled");
479     GST_OBJECT_UNLOCK (test_clock);
480     return GST_CLOCK_UNSCHEDULED;
481   }
482 }
483
484 static void
485 gst_test_clock_unschedule (GstClock * clock, GstClockEntry * entry)
486 {
487   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
488
489   GST_OBJECT_LOCK (test_clock);
490
491   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
492       "unscheduling requested clock notification at %" GST_TIME_FORMAT,
493       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
494
495   GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_UNSCHEDULED;
496   gst_test_clock_remove_entry (test_clock, entry);
497
498   GST_OBJECT_UNLOCK (test_clock);
499 }
500
501 static gboolean
502 gst_test_clock_peek_next_pending_id_unlocked (GstTestClock * test_clock,
503     GstClockID * pending_id)
504 {
505   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
506   GList *imminent_clock_id = g_list_first (priv->entry_contexts);
507   gboolean result = FALSE;
508
509   if (imminent_clock_id != NULL) {
510     GstClockEntryContext *ctx = imminent_clock_id->data;
511
512     if (pending_id != NULL) {
513       *pending_id = gst_clock_id_ref (ctx->clock_entry);
514     }
515
516     result = TRUE;
517   }
518
519   return result;
520 }
521
522 static guint
523 gst_test_clock_peek_id_count_unlocked (GstTestClock * test_clock)
524 {
525   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
526
527   return g_list_length (priv->entry_contexts);
528 }
529
530 static void
531 gst_test_clock_add_entry (GstTestClock * test_clock,
532     GstClockEntry * entry, GstClockTimeDiff * jitter)
533 {
534   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
535   GstClockTime now;
536   GstClockEntryContext *ctx;
537
538   now = gst_clock_adjust_unlocked (GST_CLOCK (test_clock), priv->internal_time);
539
540   if (jitter != NULL)
541     *jitter = GST_CLOCK_DIFF (GST_CLOCK_ENTRY_TIME (entry), now);
542
543   ctx = g_slice_new (GstClockEntryContext);
544   ctx->clock_entry = GST_CLOCK_ENTRY (gst_clock_id_ref (entry));
545   ctx->time_diff = GST_CLOCK_DIFF (now, GST_CLOCK_ENTRY_TIME (entry));
546
547   priv->entry_contexts = g_list_insert_sorted (priv->entry_contexts, ctx,
548       gst_clock_entry_context_compare_func);
549
550   g_cond_broadcast (&priv->entry_added_cond);
551 }
552
553 static void
554 gst_test_clock_remove_entry (GstTestClock * test_clock, GstClockEntry * entry)
555 {
556   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
557   GstClockEntryContext *ctx;
558
559   ctx = gst_test_clock_lookup_entry_context (test_clock, entry);
560   if (ctx != NULL) {
561     gst_clock_id_unref (ctx->clock_entry);
562     priv->entry_contexts = g_list_remove (priv->entry_contexts, ctx);
563     g_slice_free (GstClockEntryContext, ctx);
564
565     g_cond_broadcast (&priv->entry_processed_cond);
566   }
567 }
568
569 static GstClockEntryContext *
570 gst_test_clock_lookup_entry_context (GstTestClock * test_clock,
571     GstClockEntry * clock_entry)
572 {
573   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
574   GstClockEntryContext *result = NULL;
575   GList *cur;
576
577   for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
578     GstClockEntryContext *ctx = cur->data;
579
580     if (ctx->clock_entry == clock_entry) {
581       result = ctx;
582       break;
583     }
584   }
585
586   return result;
587 }
588
589 static gint
590 gst_clock_entry_context_compare_func (gconstpointer a, gconstpointer b)
591 {
592   const GstClockEntryContext *ctx_a = a;
593   const GstClockEntryContext *ctx_b = b;
594
595   return gst_clock_id_compare_func (ctx_a->clock_entry, ctx_b->clock_entry);
596 }
597
598 static void
599 process_entry_context_unlocked (GstTestClock * test_clock,
600     GstClockEntryContext * ctx)
601 {
602   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
603   GstClockEntry *entry = ctx->clock_entry;
604
605   if (ctx->time_diff >= 0)
606     GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK;
607   else
608     GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_EARLY;
609
610   if (entry->func != NULL) {
611     GST_OBJECT_UNLOCK (test_clock);
612     entry->func (GST_CLOCK (test_clock), priv->internal_time, entry,
613         entry->user_data);
614     GST_OBJECT_LOCK (test_clock);
615   }
616
617   gst_test_clock_remove_entry (test_clock, entry);
618
619   if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_PERIODIC) {
620     GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry);
621
622     if (entry->func != NULL)
623       gst_test_clock_add_entry (test_clock, entry, NULL);
624   }
625 }
626
627 static GList *
628 gst_test_clock_get_pending_id_list_unlocked (GstTestClock * test_clock)
629 {
630   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
631   GQueue queue = G_QUEUE_INIT;
632   GList *cur;
633
634   for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
635     GstClockEntryContext *ctx = cur->data;
636
637     g_queue_push_tail (&queue, gst_clock_id_ref (ctx->clock_entry));
638   }
639
640   return queue.head;
641 }
642
643 /**
644  * gst_test_clock_new:
645  *
646  * Creates a new test clock with its time set to zero.
647  *
648  * MT safe.
649  *
650  * Returns: (transfer full): a #GstTestClock cast to #GstClock.
651  *
652  * Since: 1.2
653  */
654 GstClock *
655 gst_test_clock_new (void)
656 {
657   return gst_test_clock_new_with_start_time (0);
658 }
659
660 /**
661  * gst_test_clock_new_with_start_time:
662  * @start_time: a #GstClockTime set to the desired start time of the clock.
663  *
664  * Creates a new test clock with its time set to the specified time.
665  *
666  * MT safe.
667  *
668  * Returns: (transfer full): a #GstTestClock cast to #GstClock.
669  *
670  * Since: 1.2
671  */
672 GstClock *
673 gst_test_clock_new_with_start_time (GstClockTime start_time)
674 {
675   g_assert_cmpuint (start_time, !=, GST_CLOCK_TIME_NONE);
676   return g_object_new (GST_TYPE_TEST_CLOCK, "start-time", start_time, NULL);
677 }
678
679 /**
680  * gst_test_clock_set_time:
681  * @test_clock: a #GstTestClock of which to set the time
682  * @new_time: a #GstClockTime later than that returned by gst_clock_get_time()
683  *
684  * Sets the time of @test_clock to the time given by @new_time. The time of
685  * @test_clock is monotonically increasing, therefore providing a @new_time
686  * which is earlier or equal to the time of the clock as given by
687  * gst_clock_get_time() is a programming error.
688  *
689  * MT safe.
690  *
691  * Since: 1.2
692  */
693 void
694 gst_test_clock_set_time (GstTestClock * test_clock, GstClockTime new_time)
695 {
696   GstTestClockPrivate *priv;
697
698   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
699
700   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
701
702   g_assert_cmpuint (new_time, !=, GST_CLOCK_TIME_NONE);
703
704   GST_OBJECT_LOCK (test_clock);
705
706   g_assert_cmpuint (new_time, >=, priv->internal_time);
707
708   priv->internal_time = new_time;
709   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
710       "clock set to %" GST_TIME_FORMAT, GST_TIME_ARGS (new_time));
711
712   GST_OBJECT_UNLOCK (test_clock);
713 }
714
715 /**
716  * gst_test_clock_advance_time:
717  * @test_clock: a #GstTestClock for which to increase the time
718  * @delta: a positive #GstClockTimeDiff to be added to the time of the clock
719  *
720  * Advances the time of the @test_clock by the amount given by @delta. The
721  * time of @test_clock is monotonically increasing, therefore providing a
722  * @delta which is negative or zero is a programming error.
723  *
724  * MT safe.
725  *
726  * Since: 1.2
727  */
728 void
729 gst_test_clock_advance_time (GstTestClock * test_clock, GstClockTimeDiff delta)
730 {
731   GstTestClockPrivate *priv;
732
733   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
734
735   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
736
737   g_assert_cmpint (delta, >=, 0);
738   g_assert_cmpuint (delta, <, G_MAXUINT64 - delta);
739
740   GST_OBJECT_LOCK (test_clock);
741
742   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
743       "advancing clock by %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
744       GST_TIME_ARGS (delta), GST_TIME_ARGS (priv->internal_time + delta));
745   priv->internal_time += delta;
746
747   GST_OBJECT_UNLOCK (test_clock);
748 }
749
750 /**
751  * gst_test_clock_peek_id_count:
752  * @test_clock: a #GstTestClock for which to count notifications
753  *
754  * Determine the number of pending clock notifications that have been
755  * requested from the @test_clock.
756  *
757  * MT safe.
758  *
759  * Returns: the number of pending clock notifications.
760  *
761  * Since: 1.2
762  */
763 guint
764 gst_test_clock_peek_id_count (GstTestClock * test_clock)
765 {
766   guint result;
767
768   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
769
770   GST_OBJECT_LOCK (test_clock);
771   result = gst_test_clock_peek_id_count_unlocked (test_clock);
772   GST_OBJECT_UNLOCK (test_clock);
773
774   return result;
775 }
776
777 /**
778  * gst_test_clock_has_id:
779  * @test_clock: a #GstTestClock to ask if it provided the notification
780  * @id: (transfer none): a #GstClockID clock notification
781  *
782  * Checks whether @test_clock was requested to provide the clock notification
783  * given by @id.
784  *
785  * MT safe.
786  *
787  * Returns: %TRUE if the clock has been asked to provide the given clock
788  * notification, %FALSE otherwise.
789  *
790  * Since: 1.2
791  */
792 gboolean
793 gst_test_clock_has_id (GstTestClock * test_clock, GstClockID id)
794 {
795   gboolean result;
796
797   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
798   g_assert (id != NULL);
799
800   GST_OBJECT_LOCK (test_clock);
801   result = gst_test_clock_lookup_entry_context (test_clock, id) != NULL;
802   GST_OBJECT_UNLOCK (test_clock);
803
804   return result;
805 }
806
807 /**
808  * gst_test_clock_peek_next_pending_id:
809  * @test_clock: a #GstTestClock to check the clock notifications for
810  * @pending_id: (allow-none) (out) (transfer full): a #GstClockID clock
811  * notification to look for
812  *
813  * Determines if the @pending_id is the next clock notification scheduled to
814  * be triggered given the current time of the @test_clock.
815  *
816  * MT safe.
817  *
818  * Return: %TRUE if @pending_id is the next clock notification to be
819  * triggered, %FALSE otherwise.
820  *
821  * Since: 1.2
822  */
823 gboolean
824 gst_test_clock_peek_next_pending_id (GstTestClock * test_clock,
825     GstClockID * pending_id)
826 {
827   gboolean result;
828
829   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
830
831   GST_OBJECT_LOCK (test_clock);
832   result = gst_test_clock_peek_next_pending_id_unlocked (test_clock,
833       pending_id);
834   GST_OBJECT_UNLOCK (test_clock);
835
836   return result;
837 }
838
839 /**
840  * gst_test_clock_wait_for_next_pending_id:
841  * @test_clock: #GstTestClock for which to get the pending clock notification
842  * @pending_id: (allow-none) (out) (transfer full): #GstClockID
843  * with information about the pending clock notification
844  *
845  * Waits until a clock notification is requested from @test_clock. There is no
846  * timeout for this wait, see the main description of #GstTestClock. A reference
847  * to the pending clock notification is stored in @pending_id.
848  *
849  * MT safe.
850  *
851  * Since: 1.2
852  */
853 void
854 gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock,
855     GstClockID * pending_id)
856 {
857   GstTestClockPrivate *priv;
858
859   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
860
861   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
862
863   GST_OBJECT_LOCK (test_clock);
864
865   while (priv->entry_contexts == NULL)
866     g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock));
867
868   if (!gst_test_clock_peek_next_pending_id_unlocked (test_clock, pending_id))
869     g_assert_not_reached ();
870
871   GST_OBJECT_UNLOCK (test_clock);
872 }
873
874 /**
875  * gst_test_clock_wait_for_pending_id_count:
876  * @test_clock: #GstTestClock for which to await having enough pending clock
877  * @count: the number of pending clock notifications to wait for
878  *
879  * Blocks until at least @count clock notifications have been requested from
880  * @test_clock. There is no timeout for this wait, see the main description of
881  * #GstTestClock.
882  *
883  * Since: 1.2
884  *
885  * Deprecated: use gst_test_clock_wait_for_multiple_pending_ids() instead.
886  */
887 #ifndef GST_REMOVE_DEPRECATED
888 #ifdef GST_DISABLE_DEPRECATED
889 void gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock,
890     guint count);
891 #endif
892 void
893 gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock,
894     guint count)
895 {
896   gst_test_clock_wait_for_multiple_pending_ids (test_clock, count, NULL);
897 }
898 #endif
899
900 /**
901  * gst_test_clock_process_next_clock_id:
902  * @test_clock: a #GstTestClock for which to retrieve the next pending clock
903  * notification
904  *
905  * MT safe.
906  *
907  * Returns: (transfer full): a #GstClockID containing the next pending clock
908  * notification.
909  *
910  * Since: 1.2
911  */
912 GstClockID
913 gst_test_clock_process_next_clock_id (GstTestClock * test_clock)
914 {
915   GstTestClockPrivate *priv;
916   GstClockID result = NULL;
917   GstClockEntryContext *ctx = NULL;
918   GList *cur;
919
920   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), NULL);
921
922   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
923
924   GST_OBJECT_LOCK (test_clock);
925
926   for (cur = priv->entry_contexts; cur != NULL && result == NULL;
927       cur = cur->next) {
928     ctx = cur->data;
929
930     if (priv->internal_time >= GST_CLOCK_ENTRY_TIME (ctx->clock_entry))
931       result = gst_clock_id_ref (ctx->clock_entry);
932   }
933
934   if (result != NULL)
935     process_entry_context_unlocked (test_clock, ctx);
936
937   GST_OBJECT_UNLOCK (test_clock);
938
939   return result;
940 }
941
942 /**
943  * gst_test_clock_get_next_entry_time:
944  * @test_clock: a #GstTestClock to fetch the next clock notification time for
945  *
946  * Retrieve the requested time for the next pending clock notification.
947  *
948  * MT safe.
949  *
950  * Returns: a #GstClockTime set to the time of the next pending clock
951  * notification. If no clock notifications have been requested
952  * %GST_CLOCK_TIME_NONE will be returned.
953  *
954  * Since: 1.2
955  */
956 GstClockTime
957 gst_test_clock_get_next_entry_time (GstTestClock * test_clock)
958 {
959   GstTestClockPrivate *priv;
960   GstClockTime result = GST_CLOCK_TIME_NONE;
961   GList *imminent_clock_id;
962
963   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), GST_CLOCK_TIME_NONE);
964
965   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
966
967   GST_OBJECT_LOCK (test_clock);
968
969   /* The list of pending clock notifications is sorted by time,
970      so the most imminent one is the first one in the list. */
971   imminent_clock_id = g_list_first (priv->entry_contexts);
972   if (imminent_clock_id != NULL) {
973     GstClockEntryContext *ctx = imminent_clock_id->data;
974     result = GST_CLOCK_ENTRY_TIME (ctx->clock_entry);
975   }
976
977   GST_OBJECT_UNLOCK (test_clock);
978
979   return result;
980 }
981
982 /**
983  * gst_test_clock_wait_for_multiple_pending_ids:
984  * @test_clock: #GstTestClock for which to await having enough pending clock
985  * @count: the number of pending clock notifications to wait for
986  * @pending_list: (out) (element-type Gst.ClockID) (transfer full) (allow-none): Address
987  *     of a #GList pointer variable to store the list of pending #GstClockIDs
988  *     that expired, or %NULL
989  *
990  * Blocks until at least @count clock notifications have been requested from
991  * @test_clock. There is no timeout for this wait, see the main description of
992  * #GstTestClock.
993  *
994  * MT safe.
995  *
996  * Since: 1.4
997  */
998 void
999 gst_test_clock_wait_for_multiple_pending_ids (GstTestClock * test_clock,
1000     guint count, GList ** pending_list)
1001 {
1002   GstTestClockPrivate *priv;
1003
1004   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
1005   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
1006
1007   GST_OBJECT_LOCK (test_clock);
1008
1009   while (g_list_length (priv->entry_contexts) < count)
1010     g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock));
1011
1012   if (pending_list)
1013     *pending_list = gst_test_clock_get_pending_id_list_unlocked (test_clock);
1014
1015   GST_OBJECT_UNLOCK (test_clock);
1016 }
1017
1018 /**
1019  * gst_test_clock_process_id_list:
1020  * @test_clock: #GstTestClock for which to process the pending IDs
1021  * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List
1022  *     of pending #GstClockIDs
1023  *
1024  * Processes and releases the pending IDs in the list.
1025  *
1026  * MT safe.
1027  *
1028  * Since: 1.4
1029  */
1030 guint
1031 gst_test_clock_process_id_list (GstTestClock * test_clock,
1032     const GList * pending_list)
1033 {
1034   const GList *cur;
1035   guint result = 0;
1036
1037   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
1038
1039   GST_OBJECT_LOCK (test_clock);
1040
1041   for (cur = pending_list; cur != NULL; cur = cur->next) {
1042     GstClockID pending_id = cur->data;
1043     GstClockEntryContext *ctx =
1044         gst_test_clock_lookup_entry_context (test_clock, pending_id);
1045     if (ctx) {
1046       process_entry_context_unlocked (test_clock, ctx);
1047       result++;
1048     }
1049   }
1050   GST_OBJECT_UNLOCK (test_clock);
1051
1052   return result;
1053 }
1054
1055 /**
1056  * gst_test_clock_id_list_get_latest_time:
1057  * @pending_list:  (element-type Gst.ClockID) (transfer none) (allow-none): List
1058  *     of of pending #GstClockIDs
1059  *
1060  * Finds the latest time inside the list.
1061  *
1062  * MT safe.
1063  *
1064  * Since: 1.4
1065  */
1066 GstClockTime
1067 gst_test_clock_id_list_get_latest_time (const GList * pending_list)
1068 {
1069   const GList *cur;
1070   GstClockTime result = 0;
1071
1072   for (cur = pending_list; cur != NULL; cur = cur->next) {
1073     GstClockID *pending_id = cur->data;
1074     GstClockTime time = gst_clock_id_get_time (pending_id);
1075     if (time > result)
1076       result = time;
1077   }
1078
1079   return result;
1080 }