• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, G_ADD_PRIVATE (GstTestClock) _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
gst_test_clock_class_init(GstTestClockClass * klass)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   gobject_class->constructed = GST_DEBUG_FUNCPTR (gst_test_clock_constructed);
265   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_test_clock_dispose);
266   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_test_clock_finalize);
267   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_test_clock_get_property);
268   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_test_clock_set_property);
269 
270   gstclock_class->get_resolution =
271       GST_DEBUG_FUNCPTR (gst_test_clock_get_resolution);
272   gstclock_class->get_internal_time =
273       GST_DEBUG_FUNCPTR (gst_test_clock_get_internal_time);
274   gstclock_class->wait = GST_DEBUG_FUNCPTR (gst_test_clock_wait);
275   gstclock_class->wait_async = GST_DEBUG_FUNCPTR (gst_test_clock_wait_async);
276   gstclock_class->unschedule = GST_DEBUG_FUNCPTR (gst_test_clock_unschedule);
277 
278   /**
279    * GstTestClock:start-time:
280    *
281    * When a #GstTestClock is constructed it will have a certain start time set.
282    * If the clock was created using gst_test_clock_new_with_start_time() then
283    * this property contains the value of the @start_time argument. If
284    * gst_test_clock_new() was called the clock started at time zero, and thus
285    * this property contains the value 0.
286    */
287   pspec = g_param_spec_uint64 ("start-time", "Start Time",
288       "Start Time of the Clock", 0, G_MAXUINT64, 0,
289       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
290   g_object_class_install_property (gobject_class, PROP_START_TIME, pspec);
291 
292   g_object_class_install_property (gobject_class, PROP_CLOCK_TYPE,
293       g_param_spec_enum ("clock-type", "Clock type",
294           "The kind of clock implementation to be reported by this clock",
295           GST_TYPE_CLOCK_TYPE, DEFAULT_CLOCK_TYPE,
296           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
297 
298 }
299 
300 static void
gst_test_clock_init(GstTestClock * test_clock)301 gst_test_clock_init (GstTestClock * test_clock)
302 {
303   GstTestClockPrivate *priv;
304 
305   test_clock->priv = gst_test_clock_get_instance_private (test_clock);
306 
307   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
308 
309   g_cond_init (&priv->entry_added_cond);
310   g_cond_init (&priv->entry_processed_cond);
311   priv->clock_type = DEFAULT_CLOCK_TYPE;
312 
313   GST_OBJECT_FLAG_SET (test_clock,
314       GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
315       GST_CLOCK_FLAG_CAN_DO_SINGLE_ASYNC |
316       GST_CLOCK_FLAG_CAN_DO_PERIODIC_SYNC |
317       GST_CLOCK_FLAG_CAN_DO_PERIODIC_ASYNC);
318 }
319 
320 static void
gst_test_clock_constructed(GObject * object)321 gst_test_clock_constructed (GObject * object)
322 {
323   GstTestClock *test_clock = GST_TEST_CLOCK (object);
324   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
325 
326   priv->internal_time = priv->start_time;
327 
328   G_OBJECT_CLASS (parent_class)->constructed (object);
329 }
330 
331 static void
gst_test_clock_dispose(GObject * object)332 gst_test_clock_dispose (GObject * object)
333 {
334   GstTestClock *test_clock = GST_TEST_CLOCK (object);
335   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
336 
337   GST_OBJECT_LOCK (test_clock);
338 
339   while (priv->entry_contexts != NULL) {
340     GstClockEntryContext *ctx = priv->entry_contexts->data;
341     gst_test_clock_remove_entry (test_clock, ctx->clock_entry);
342   }
343 
344   GST_OBJECT_UNLOCK (test_clock);
345 
346   G_OBJECT_CLASS (parent_class)->dispose (object);
347 }
348 
349 static void
gst_test_clock_finalize(GObject * object)350 gst_test_clock_finalize (GObject * object)
351 {
352   GstTestClock *test_clock = GST_TEST_CLOCK (object);
353   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
354 
355   g_cond_clear (&priv->entry_added_cond);
356   g_cond_clear (&priv->entry_processed_cond);
357 
358   G_OBJECT_CLASS (parent_class)->finalize (object);
359 }
360 
361 static void
gst_test_clock_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)362 gst_test_clock_get_property (GObject * object, guint property_id,
363     GValue * value, GParamSpec * pspec)
364 {
365   GstTestClock *test_clock = GST_TEST_CLOCK (object);
366   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
367 
368   switch (property_id) {
369     case PROP_START_TIME:
370       g_value_set_uint64 (value, priv->start_time);
371       break;
372     case PROP_CLOCK_TYPE:
373       g_value_set_enum (value, priv->clock_type);
374       break;
375     default:
376       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
377       break;
378   }
379 }
380 
381 static void
gst_test_clock_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)382 gst_test_clock_set_property (GObject * object, guint property_id,
383     const GValue * value, GParamSpec * pspec)
384 {
385   GstTestClock *test_clock = GST_TEST_CLOCK (object);
386   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
387 
388   switch (property_id) {
389     case PROP_START_TIME:
390       priv->start_time = g_value_get_uint64 (value);
391       GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
392           "test clock start time initialized at %" GST_TIME_FORMAT,
393           GST_TIME_ARGS (priv->start_time));
394       break;
395     case PROP_CLOCK_TYPE:
396       priv->clock_type = (GstClockType) g_value_get_enum (value);
397       GST_CAT_DEBUG (GST_CAT_TEST_CLOCK, "clock-type set to %d",
398           priv->clock_type);
399       break;
400     default:
401       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
402       break;
403   }
404 }
405 
406 static GstClockTime
gst_test_clock_get_resolution(GstClock * clock)407 gst_test_clock_get_resolution (GstClock * clock)
408 {
409   (void) clock;
410   return 1;
411 }
412 
413 static GstClockTime
gst_test_clock_get_internal_time(GstClock * clock)414 gst_test_clock_get_internal_time (GstClock * clock)
415 {
416   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
417   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
418   GstClockTime result;
419 
420   GST_OBJECT_LOCK (test_clock);
421 
422   GST_CAT_TRACE_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
423       "retrieving test clock time %" GST_TIME_FORMAT,
424       GST_TIME_ARGS (priv->internal_time));
425   result = priv->internal_time;
426 
427   GST_OBJECT_UNLOCK (test_clock);
428 
429   return result;
430 }
431 
432 static GstClockReturn
gst_test_clock_wait(GstClock * clock,GstClockEntry * entry,GstClockTimeDiff * jitter)433 gst_test_clock_wait (GstClock * clock,
434     GstClockEntry * entry, GstClockTimeDiff * jitter)
435 {
436   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
437   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
438 
439   GST_OBJECT_LOCK (test_clock);
440 
441   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
442       "requesting synchronous clock notification at %" GST_TIME_FORMAT,
443       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
444 
445   if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)
446     goto was_unscheduled;
447 
448   if (gst_test_clock_lookup_entry_context (test_clock, entry) == NULL)
449     gst_test_clock_add_entry (test_clock, entry, jitter);
450 
451   GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_BUSY;
452 
453   while (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_BUSY)
454     g_cond_wait (&priv->entry_processed_cond, GST_OBJECT_GET_LOCK (test_clock));
455 
456   GST_OBJECT_UNLOCK (test_clock);
457 
458   return GST_CLOCK_ENTRY_STATUS (entry);
459 
460   /* ERRORS */
461 was_unscheduled:
462   {
463     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
464         "entry was unscheduled");
465     GST_OBJECT_UNLOCK (test_clock);
466     return GST_CLOCK_UNSCHEDULED;
467   }
468 }
469 
470 static GstClockReturn
gst_test_clock_wait_async(GstClock * clock,GstClockEntry * entry)471 gst_test_clock_wait_async (GstClock * clock, GstClockEntry * entry)
472 {
473   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
474 
475   GST_OBJECT_LOCK (test_clock);
476 
477   if (GST_CLOCK_ENTRY_STATUS (entry) == GST_CLOCK_UNSCHEDULED)
478     goto was_unscheduled;
479 
480   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
481       "requesting asynchronous clock notification at %" GST_TIME_FORMAT,
482       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
483 
484   gst_test_clock_add_entry (test_clock, entry, NULL);
485 
486   GST_OBJECT_UNLOCK (test_clock);
487 
488   return GST_CLOCK_OK;
489 
490   /* ERRORS */
491 was_unscheduled:
492   {
493     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
494         "entry was unscheduled");
495     GST_OBJECT_UNLOCK (test_clock);
496     return GST_CLOCK_UNSCHEDULED;
497   }
498 }
499 
500 static void
gst_test_clock_unschedule(GstClock * clock,GstClockEntry * entry)501 gst_test_clock_unschedule (GstClock * clock, GstClockEntry * entry)
502 {
503   GstTestClock *test_clock = GST_TEST_CLOCK (clock);
504 
505   GST_OBJECT_LOCK (test_clock);
506 
507   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
508       "unscheduling requested clock notification at %" GST_TIME_FORMAT,
509       GST_TIME_ARGS (GST_CLOCK_ENTRY_TIME (entry)));
510 
511   GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_UNSCHEDULED;
512   gst_test_clock_remove_entry (test_clock, entry);
513 
514   GST_OBJECT_UNLOCK (test_clock);
515 }
516 
517 static gboolean
gst_test_clock_peek_next_pending_id_unlocked(GstTestClock * test_clock,GstClockID * pending_id)518 gst_test_clock_peek_next_pending_id_unlocked (GstTestClock * test_clock,
519     GstClockID * pending_id)
520 {
521   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
522   GList *imminent_clock_id = g_list_first (priv->entry_contexts);
523   gboolean result = FALSE;
524 
525   if (imminent_clock_id != NULL) {
526     GstClockEntryContext *ctx = imminent_clock_id->data;
527 
528     if (pending_id != NULL) {
529       *pending_id = gst_clock_id_ref (ctx->clock_entry);
530     }
531 
532     result = TRUE;
533   }
534 
535   return result;
536 }
537 
538 static guint
gst_test_clock_peek_id_count_unlocked(GstTestClock * test_clock)539 gst_test_clock_peek_id_count_unlocked (GstTestClock * test_clock)
540 {
541   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
542 
543   return g_list_length (priv->entry_contexts);
544 }
545 
546 static void
gst_test_clock_add_entry(GstTestClock * test_clock,GstClockEntry * entry,GstClockTimeDiff * jitter)547 gst_test_clock_add_entry (GstTestClock * test_clock,
548     GstClockEntry * entry, GstClockTimeDiff * jitter)
549 {
550   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
551   GstClockTime now;
552   GstClockEntryContext *ctx;
553 
554   now = gst_clock_adjust_unlocked (GST_CLOCK (test_clock), priv->internal_time);
555 
556   if (jitter != NULL)
557     *jitter = GST_CLOCK_DIFF (GST_CLOCK_ENTRY_TIME (entry), now);
558 
559   ctx = g_slice_new (GstClockEntryContext);
560   ctx->clock_entry = GST_CLOCK_ENTRY (gst_clock_id_ref (entry));
561   ctx->time_diff = GST_CLOCK_DIFF (now, GST_CLOCK_ENTRY_TIME (entry));
562 
563   priv->entry_contexts = g_list_insert_sorted (priv->entry_contexts, ctx,
564       gst_clock_entry_context_compare_func);
565 
566   g_cond_broadcast (&priv->entry_added_cond);
567 }
568 
569 static void
gst_test_clock_remove_entry(GstTestClock * test_clock,GstClockEntry * entry)570 gst_test_clock_remove_entry (GstTestClock * test_clock, GstClockEntry * entry)
571 {
572   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
573   GstClockEntryContext *ctx;
574 
575   ctx = gst_test_clock_lookup_entry_context (test_clock, entry);
576   if (ctx != NULL) {
577     gst_clock_id_unref (ctx->clock_entry);
578     priv->entry_contexts = g_list_remove (priv->entry_contexts, ctx);
579     g_slice_free (GstClockEntryContext, ctx);
580 
581     g_cond_broadcast (&priv->entry_processed_cond);
582   }
583 }
584 
585 static GstClockEntryContext *
gst_test_clock_lookup_entry_context(GstTestClock * test_clock,GstClockEntry * clock_entry)586 gst_test_clock_lookup_entry_context (GstTestClock * test_clock,
587     GstClockEntry * clock_entry)
588 {
589   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
590   GstClockEntryContext *result = NULL;
591   GList *cur;
592 
593   for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
594     GstClockEntryContext *ctx = cur->data;
595 
596     if (ctx->clock_entry == clock_entry) {
597       result = ctx;
598       break;
599     }
600   }
601 
602   return result;
603 }
604 
605 static gint
gst_clock_entry_context_compare_func(gconstpointer a,gconstpointer b)606 gst_clock_entry_context_compare_func (gconstpointer a, gconstpointer b)
607 {
608   const GstClockEntryContext *ctx_a = a;
609   const GstClockEntryContext *ctx_b = b;
610 
611   return gst_clock_id_compare_func (ctx_a->clock_entry, ctx_b->clock_entry);
612 }
613 
614 static void
process_entry_context_unlocked(GstTestClock * test_clock,GstClockEntryContext * ctx)615 process_entry_context_unlocked (GstTestClock * test_clock,
616     GstClockEntryContext * ctx)
617 {
618   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
619   GstClockEntry *entry = ctx->clock_entry;
620 
621   if (ctx->time_diff >= 0)
622     GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK;
623   else
624     GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_EARLY;
625 
626   if (entry->func != NULL) {
627     GST_OBJECT_UNLOCK (test_clock);
628     entry->func (GST_CLOCK (test_clock), priv->internal_time, entry,
629         entry->user_data);
630     GST_OBJECT_LOCK (test_clock);
631   }
632 
633   gst_test_clock_remove_entry (test_clock, entry);
634 
635   if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_PERIODIC) {
636     GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry);
637 
638     if (entry->func != NULL)
639       gst_test_clock_add_entry (test_clock, entry, NULL);
640   }
641 }
642 
643 static GList *
gst_test_clock_get_pending_id_list_unlocked(GstTestClock * test_clock)644 gst_test_clock_get_pending_id_list_unlocked (GstTestClock * test_clock)
645 {
646   GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
647   GQueue queue = G_QUEUE_INIT;
648   GList *cur;
649 
650   for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
651     GstClockEntryContext *ctx = cur->data;
652 
653     g_queue_push_tail (&queue, gst_clock_id_ref (ctx->clock_entry));
654   }
655 
656   return queue.head;
657 }
658 
659 /**
660  * gst_test_clock_new:
661  *
662  * Creates a new test clock with its time set to zero.
663  *
664  * MT safe.
665  *
666  * Returns: (transfer full): a #GstTestClock cast to #GstClock.
667  *
668  * Since: 1.2
669  */
670 GstClock *
gst_test_clock_new(void)671 gst_test_clock_new (void)
672 {
673   return gst_test_clock_new_with_start_time (0);
674 }
675 
676 /**
677  * gst_test_clock_new_with_start_time:
678  * @start_time: a #GstClockTime set to the desired start time of the clock.
679  *
680  * Creates a new test clock with its time set to the specified time.
681  *
682  * MT safe.
683  *
684  * Returns: (transfer full): a #GstTestClock cast to #GstClock.
685  *
686  * Since: 1.2
687  */
688 GstClock *
gst_test_clock_new_with_start_time(GstClockTime start_time)689 gst_test_clock_new_with_start_time (GstClockTime start_time)
690 {
691   GstClock *clock;
692 
693   g_assert_cmpuint (start_time, !=, GST_CLOCK_TIME_NONE);
694   clock = g_object_new (GST_TYPE_TEST_CLOCK, "start-time", start_time, NULL);
695 
696   /* Clear floating flag */
697   gst_object_ref_sink (clock);
698 
699   return clock;
700 }
701 
702 /**
703  * gst_test_clock_set_time:
704  * @test_clock: a #GstTestClock of which to set the time
705  * @new_time: a #GstClockTime later than that returned by gst_clock_get_time()
706  *
707  * Sets the time of @test_clock to the time given by @new_time. The time of
708  * @test_clock is monotonically increasing, therefore providing a @new_time
709  * which is earlier or equal to the time of the clock as given by
710  * gst_clock_get_time() is a programming error.
711  *
712  * MT safe.
713  *
714  * Since: 1.2
715  */
716 void
gst_test_clock_set_time(GstTestClock * test_clock,GstClockTime new_time)717 gst_test_clock_set_time (GstTestClock * test_clock, GstClockTime new_time)
718 {
719   GstTestClockPrivate *priv;
720 
721   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
722 
723   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
724 
725   g_assert_cmpuint (new_time, !=, GST_CLOCK_TIME_NONE);
726 
727   GST_OBJECT_LOCK (test_clock);
728 
729   g_assert_cmpuint (new_time, >=, priv->internal_time);
730 
731   priv->internal_time = new_time;
732   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
733       "clock set to %" GST_TIME_FORMAT, GST_TIME_ARGS (new_time));
734 
735   GST_OBJECT_UNLOCK (test_clock);
736 }
737 
738 /**
739  * gst_test_clock_advance_time:
740  * @test_clock: a #GstTestClock for which to increase the time
741  * @delta: a positive #GstClockTimeDiff to be added to the time of the clock
742  *
743  * Advances the time of the @test_clock by the amount given by @delta. The
744  * time of @test_clock is monotonically increasing, therefore providing a
745  * @delta which is negative or zero is a programming error.
746  *
747  * MT safe.
748  *
749  * Since: 1.2
750  */
751 void
gst_test_clock_advance_time(GstTestClock * test_clock,GstClockTimeDiff delta)752 gst_test_clock_advance_time (GstTestClock * test_clock, GstClockTimeDiff delta)
753 {
754   GstTestClockPrivate *priv;
755 
756   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
757 
758   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
759 
760   g_assert_cmpint (delta, >=, 0);
761   g_assert_cmpuint (delta, <, G_MAXUINT64 - delta);
762 
763   GST_OBJECT_LOCK (test_clock);
764 
765   GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
766       "advancing clock by %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
767       GST_TIME_ARGS (delta), GST_TIME_ARGS (priv->internal_time + delta));
768   priv->internal_time += delta;
769 
770   GST_OBJECT_UNLOCK (test_clock);
771 }
772 
773 /**
774  * gst_test_clock_peek_id_count:
775  * @test_clock: a #GstTestClock for which to count notifications
776  *
777  * Determine the number of pending clock notifications that have been
778  * requested from the @test_clock.
779  *
780  * MT safe.
781  *
782  * Returns: the number of pending clock notifications.
783  *
784  * Since: 1.2
785  */
786 guint
gst_test_clock_peek_id_count(GstTestClock * test_clock)787 gst_test_clock_peek_id_count (GstTestClock * test_clock)
788 {
789   guint result;
790 
791   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
792 
793   GST_OBJECT_LOCK (test_clock);
794   result = gst_test_clock_peek_id_count_unlocked (test_clock);
795   GST_OBJECT_UNLOCK (test_clock);
796 
797   return result;
798 }
799 
800 /**
801  * gst_test_clock_has_id:
802  * @test_clock: a #GstTestClock to ask if it provided the notification
803  * @id: (transfer none): a #GstClockID clock notification
804  *
805  * Checks whether @test_clock was requested to provide the clock notification
806  * given by @id.
807  *
808  * MT safe.
809  *
810  * Returns: %TRUE if the clock has been asked to provide the given clock
811  * notification, %FALSE otherwise.
812  *
813  * Since: 1.2
814  */
815 gboolean
gst_test_clock_has_id(GstTestClock * test_clock,GstClockID id)816 gst_test_clock_has_id (GstTestClock * test_clock, GstClockID id)
817 {
818   gboolean result;
819 
820   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
821   g_assert (id != NULL);
822 
823   GST_OBJECT_LOCK (test_clock);
824   result = gst_test_clock_lookup_entry_context (test_clock, id) != NULL;
825   GST_OBJECT_UNLOCK (test_clock);
826 
827   return result;
828 }
829 
830 /**
831  * gst_test_clock_peek_next_pending_id:
832  * @test_clock: a #GstTestClock to check the clock notifications for
833  * @pending_id: (allow-none) (out) (transfer full): a #GstClockID clock
834  * notification to look for
835  *
836  * Determines if the @pending_id is the next clock notification scheduled to
837  * be triggered given the current time of the @test_clock.
838  *
839  * MT safe.
840  *
841  * Return: %TRUE if @pending_id is the next clock notification to be
842  * triggered, %FALSE otherwise.
843  *
844  * Since: 1.2
845  */
846 gboolean
gst_test_clock_peek_next_pending_id(GstTestClock * test_clock,GstClockID * pending_id)847 gst_test_clock_peek_next_pending_id (GstTestClock * test_clock,
848     GstClockID * pending_id)
849 {
850   gboolean result;
851 
852   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
853 
854   GST_OBJECT_LOCK (test_clock);
855   result = gst_test_clock_peek_next_pending_id_unlocked (test_clock,
856       pending_id);
857   GST_OBJECT_UNLOCK (test_clock);
858 
859   return result;
860 }
861 
862 /**
863  * gst_test_clock_wait_for_next_pending_id:
864  * @test_clock: #GstTestClock for which to get the pending clock notification
865  * @pending_id: (allow-none) (out) (transfer full): #GstClockID
866  * with information about the pending clock notification
867  *
868  * Waits until a clock notification is requested from @test_clock. There is no
869  * timeout for this wait, see the main description of #GstTestClock. A reference
870  * to the pending clock notification is stored in @pending_id.
871  *
872  * MT safe.
873  *
874  * Since: 1.2
875  */
876 void
gst_test_clock_wait_for_next_pending_id(GstTestClock * test_clock,GstClockID * pending_id)877 gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock,
878     GstClockID * pending_id)
879 {
880   GstTestClockPrivate *priv;
881 
882   g_return_if_fail (GST_IS_TEST_CLOCK (test_clock));
883 
884   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
885 
886   GST_OBJECT_LOCK (test_clock);
887 
888   while (priv->entry_contexts == NULL)
889     g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock));
890 
891   if (!gst_test_clock_peek_next_pending_id_unlocked (test_clock, pending_id))
892     g_assert_not_reached ();
893 
894   GST_OBJECT_UNLOCK (test_clock);
895 }
896 
897 /**
898  * gst_test_clock_wait_for_pending_id_count:
899  * @test_clock: #GstTestClock for which to await having enough pending clock
900  * @count: the number of pending clock notifications to wait for
901  *
902  * Blocks until at least @count clock notifications have been requested from
903  * @test_clock. There is no timeout for this wait, see the main description of
904  * #GstTestClock.
905  *
906  * Since: 1.2
907  *
908  * Deprecated: use gst_test_clock_wait_for_multiple_pending_ids() instead.
909  */
910 #ifndef GST_REMOVE_DEPRECATED
911 void
gst_test_clock_wait_for_pending_id_count(GstTestClock * test_clock,guint count)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) (nullable): a #GstClockID containing the next pending clock
927  * notification.
928  *
929  * Since: 1.2
930  */
931 GstClockID
gst_test_clock_process_next_clock_id(GstTestClock * test_clock)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
gst_test_clock_get_next_entry_time(GstTestClock * test_clock)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
gst_test_clock_wait_for_multiple_pending_ids(GstTestClock * test_clock,guint count,GList ** pending_list)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_timed_wait_for_multiple_pending_ids:
1039  * @test_clock: #GstTestClock for which to await having enough pending clock
1040  * @count: the number of pending clock notifications to wait for
1041  * @timeout_ms: the timeout in milliseconds
1042  * @pending_list: (out) (element-type Gst.ClockID) (transfer full) (allow-none): Address
1043  *     of a #GList pointer variable to store the list of pending #GstClockIDs
1044  *     that expired, or %NULL
1045  *
1046  * Blocks until at least @count clock notifications have been requested from
1047  * @test_clock, or the timeout expires.
1048  *
1049  * MT safe.
1050  *
1051  * Returns: a @gboolean %TRUE if the waits have been registered, %FALSE if not.
1052  * (Could be that it timed out waiting or that more waits than waits was found)
1053  *
1054  * Since: 1.16
1055  */
1056 gboolean
gst_test_clock_timed_wait_for_multiple_pending_ids(GstTestClock * test_clock,guint count,guint timeout_ms,GList ** pending_list)1057 gst_test_clock_timed_wait_for_multiple_pending_ids (GstTestClock * test_clock,
1058     guint count, guint timeout_ms, GList ** pending_list)
1059 {
1060   GstTestClockPrivate *priv;
1061   gint64 timeout = g_get_monotonic_time () +
1062       timeout_ms * (G_USEC_PER_SEC / 1000);
1063   gboolean ret;
1064 
1065   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
1066   priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
1067 
1068   GST_OBJECT_LOCK (test_clock);
1069 
1070   while (g_list_length (priv->entry_contexts) < count &&
1071       g_get_monotonic_time () < timeout) {
1072     g_cond_wait_until (&priv->entry_added_cond,
1073         GST_OBJECT_GET_LOCK (test_clock), timeout);
1074   }
1075 
1076   if (pending_list)
1077     *pending_list = gst_test_clock_get_pending_id_list_unlocked (test_clock);
1078 
1079   ret = (g_list_length (priv->entry_contexts) == count);
1080 
1081   GST_OBJECT_UNLOCK (test_clock);
1082 
1083   return ret;
1084 }
1085 
1086 
1087 /**
1088  * gst_test_clock_process_id:
1089  * @test_clock: #GstTestClock for which to process the pending IDs
1090  * @pending_id: (transfer full): #GstClockID
1091  *
1092  * Processes and releases the pending ID.
1093  *
1094  * MT safe.
1095  *
1096  * Since: 1.18
1097  */
1098 gboolean
gst_test_clock_process_id(GstTestClock * test_clock,GstClockID pending_id)1099 gst_test_clock_process_id (GstTestClock * test_clock, GstClockID pending_id)
1100 {
1101   GstClockEntryContext *ctx;
1102 
1103   gboolean result = FALSE;
1104 
1105   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), FALSE);
1106 
1107   GST_OBJECT_LOCK (test_clock);
1108 
1109   ctx = gst_test_clock_lookup_entry_context (test_clock, pending_id);
1110   g_assert (ctx);
1111 
1112   if (ctx) {
1113     process_entry_context_unlocked (test_clock, ctx);
1114     result = TRUE;
1115     gst_clock_id_unref (pending_id);
1116   }
1117 
1118   GST_OBJECT_UNLOCK (test_clock);
1119 
1120   return result;
1121 }
1122 
1123 /**
1124  * gst_test_clock_process_id_list:
1125  * @test_clock: #GstTestClock for which to process the pending IDs
1126  * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List
1127  *     of pending #GstClockIDs
1128  *
1129  * Processes and releases the pending IDs in the list.
1130  *
1131  * MT safe.
1132  *
1133  * Since: 1.4
1134  */
1135 guint
gst_test_clock_process_id_list(GstTestClock * test_clock,const GList * pending_list)1136 gst_test_clock_process_id_list (GstTestClock * test_clock,
1137     const GList * pending_list)
1138 {
1139   const GList *cur;
1140   guint result = 0;
1141 
1142   g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
1143 
1144   GST_OBJECT_LOCK (test_clock);
1145 
1146   for (cur = pending_list; cur != NULL; cur = cur->next) {
1147     GstClockID pending_id = cur->data;
1148     GstClockEntryContext *ctx =
1149         gst_test_clock_lookup_entry_context (test_clock, pending_id);
1150     if (ctx) {
1151       process_entry_context_unlocked (test_clock, ctx);
1152       result++;
1153     }
1154   }
1155   GST_OBJECT_UNLOCK (test_clock);
1156 
1157   return result;
1158 }
1159 
1160 /**
1161  * gst_test_clock_id_list_get_latest_time:
1162  * @pending_list:  (element-type Gst.ClockID) (transfer none) (allow-none): List
1163  *     of of pending #GstClockIDs
1164  *
1165  * Finds the latest time inside the list.
1166  *
1167  * MT safe.
1168  *
1169  * Since: 1.4
1170  */
1171 GstClockTime
gst_test_clock_id_list_get_latest_time(const GList * pending_list)1172 gst_test_clock_id_list_get_latest_time (const GList * pending_list)
1173 {
1174   const GList *cur;
1175   GstClockTime result = 0;
1176 
1177   for (cur = pending_list; cur != NULL; cur = cur->next) {
1178     GstClockID *pending_id = cur->data;
1179     GstClockTime time = gst_clock_id_get_time (pending_id);
1180     if (time > result)
1181       result = time;
1182   }
1183 
1184   return result;
1185 }
1186 
1187 /**
1188  * gst_test_clock_crank:
1189  * @test_clock: #GstTestClock to crank
1190  *
1191  * A "crank" consists of three steps:
1192  * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
1193  * 2: Advance the #GstTestClock to the time the #GstClockID is waiting, unless
1194  *    the clock time is already passed the clock id (Since: 1.18).
1195  * 3: Release the #GstClockID wait.
1196  * A "crank" can be though of as the notion of
1197  * manually driving the clock forward to its next logical step.
1198  *
1199  * Return: %TRUE if the crank was successful, %FALSE otherwise.
1200  *
1201  * MT safe.
1202  *
1203  * Since: 1.8
1204  */
1205 gboolean
gst_test_clock_crank(GstTestClock * test_clock)1206 gst_test_clock_crank (GstTestClock * test_clock)
1207 {
1208   GstClockID res, pending;
1209   GstClockTime now;
1210   gboolean result;
1211 
1212   gst_test_clock_wait_for_next_pending_id (test_clock, &pending);
1213   now = gst_clock_get_time (GST_CLOCK (test_clock));
1214   if (gst_clock_id_get_time (pending) > now)
1215     gst_test_clock_set_time (test_clock, gst_clock_id_get_time (pending));
1216   res = gst_test_clock_process_next_clock_id (test_clock);
1217   if (G_LIKELY (res == pending)) {
1218     GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
1219         "cranked to time %" GST_TIME_FORMAT,
1220         GST_TIME_ARGS (gst_clock_get_time (GST_CLOCK (test_clock))));
1221     result = TRUE;
1222   } else {
1223     GST_CAT_WARNING_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
1224         "testclock next id != pending (%p != %p)", res, pending);
1225     result = FALSE;
1226   }
1227 
1228   if (G_LIKELY (res != NULL))
1229     gst_clock_id_unref (res);
1230 
1231   gst_clock_id_unref (pending);
1232 
1233   return result;
1234 }
1235