/**
* SECTION:gsttestclock
+ * @title: GstTestClock
* @short_description: Controllable, deterministic clock for GStreamer unit tests
* @see_also: #GstSystemClock, #GstClock
*
* precisely advance the time in a deterministic manner, independent of the
* system time or any other external factors.
*
- * <example>
- * <title>Advancing the time of a #GstTestClock</title>
- * <programlisting language="c">
- * #include <gst/gst.h>
- * #include <gst/check/gsttestclock.h>
+ * ## Advancing the time of a #GstTestClock
+ *
+ * |[<!-- language="C" -->
+ * #include <gst/gst.h>
+ * #include <gst/check/gsttestclock.h>
*
* GstClock *clock;
* GstTestClock *test_clock;
* gst_test_clock_set_time (test_clock, 42 * GST_SECOND);
* GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
* ...
- * </programlisting>
- * </example>
+ * ]|
*
* #GstClock allows for setting up single shot or periodic clock notifications
* as well as waiting for these notifications synchronously (using
* second buffer will arrive a little late (7ms) due to simulated jitter in the
* clock notification.
*
- * <example>
- * <title>Demonstration of how to work with clock notifications and #GstTestClock</title>
- * <programlisting language="c">
- * #include <gst/gst.h>
- * #include <gst/check/gstcheck.h>
- * #include <gst/check/gsttestclock.h>
+ * ## Demonstration of how to work with clock notifications and #GstTestClock
+ *
+ * |[<!-- language="C" -->
+ * #include <gst/gst.h>
+ * #include <gst/check/gstcheck.h>
+ * #include <gst/check/gsttestclock.h>
*
* GstClockTime latency;
* GstElement *element;
* g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==, latency);
* gst_buffer_unref (buf);
* GST_INFO ("Check that element does not wait for any clock notification\n");
- * g_assert (gst_test_clock_peek_next_pending_id (test_clock, NULL) == FALSE);
+ * g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
*
* GST_INFO ("Set time, create and push the second buffer\n");
* gst_test_clock_advance_time (test_clock, 10 * GST_SECOND);
* 10 * GST_SECOND + latency + 7 * GST_MSECOND);
* gst_buffer_unref (buf);
* GST_INFO ("Check that element does not wait for any clock notification\n");
- * g_assert (gst_test_clock_peek_next_pending_id (test_clock, NULL) == FALSE);
+ * g_assert (!gst_test_clock_peek_next_pending_id (test_clock, NULL));
* ...
- * </programlisting>
- * </example>
+ * ]|
*
* Since #GstTestClock is only supposed to be used in unit tests it calls
* g_assert(), g_assert_cmpint() or g_assert_cmpuint() to validate all function
enum
{
PROP_0,
- PROP_START_TIME
+ PROP_START_TIME,
+ PROP_CLOCK_TYPE
};
typedef struct _GstClockEntryContext GstClockEntryContext;
struct _GstTestClockPrivate
{
+ GstClockType clock_type;
GstClockTime start_time;
GstClockTime internal_time;
GList *entry_contexts;
GCond entry_processed_cond;
};
+#define DEFAULT_CLOCK_TYPE GST_CLOCK_TYPE_MONOTONIC
+
#define GST_TEST_CLOCK_GET_PRIVATE(obj) ((GST_TEST_CLOCK_CAST (obj))->priv)
GST_DEBUG_CATEGORY_STATIC (test_clock_debug);
"Start Time of the Clock", 0, G_MAXUINT64, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (gobject_class, PROP_START_TIME, pspec);
+
+ g_object_class_install_property (gobject_class, PROP_CLOCK_TYPE,
+ g_param_spec_enum ("clock-type", "Clock type",
+ "The kind of clock implementation to be reported by this clock",
+ GST_TYPE_CLOCK_TYPE, DEFAULT_CLOCK_TYPE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
}
static void
g_cond_init (&priv->entry_added_cond);
g_cond_init (&priv->entry_processed_cond);
+ priv->clock_type = DEFAULT_CLOCK_TYPE;
GST_OBJECT_FLAG_SET (test_clock,
GST_CLOCK_FLAG_CAN_DO_SINGLE_SYNC |
case PROP_START_TIME:
g_value_set_uint64 (value, priv->start_time);
break;
+ case PROP_CLOCK_TYPE:
+ g_value_set_enum (value, priv->clock_type);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
"test clock start time initialized at %" GST_TIME_FORMAT,
GST_TIME_ARGS (priv->start_time));
break;
+ case PROP_CLOCK_TYPE:
+ priv->clock_type = (GstClockType) g_value_get_enum (value);
+ GST_CAT_DEBUG (GST_CAT_TEST_CLOCK, "clock-type set to %d",
+ priv->clock_type);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
-static GstTestClockIDList *
+static GList *
gst_test_clock_get_pending_id_list_unlocked (GstTestClock * test_clock)
{
GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock);
- GstTestClockIDList *result = g_new0 (GstTestClockIDList, 1);
+ GQueue queue = G_QUEUE_INIT;
+ GList *cur;
- if (priv->entry_contexts != NULL) {
- GList *cur;
- for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
- GstClockEntryContext *ctx = cur->data;
+ for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) {
+ GstClockEntryContext *ctx = cur->data;
- result->cur =
- g_list_append (result->cur, gst_clock_id_ref (ctx->clock_entry));
- }
+ g_queue_push_tail (&queue, gst_clock_id_ref (ctx->clock_entry));
}
- result->length = g_list_length (result->cur);
- return result;
+ return queue.head;
}
/**
* gst_test_clock_wait_for_multiple_pending_ids:
* @test_clock: #GstTestClock for which to await having enough pending clock
* @count: the number of pending clock notifications to wait for
- * @pending_list: A #GstTestClockIDList with pending #GstClockIDs
+ * @pending_list: (out) (element-type Gst.ClockID) (transfer full) (allow-none): Address
+ * of a #GList pointer variable to store the list of pending #GstClockIDs
+ * that expired, or %NULL
*
* Blocks until at least @count clock notifications have been requested from
* @test_clock. There is no timeout for this wait, see the main description of
*/
void
gst_test_clock_wait_for_multiple_pending_ids (GstTestClock * test_clock,
- guint count, GstTestClockIDList ** pending_list)
+ guint count, GList ** pending_list)
{
GstTestClockPrivate *priv;
/**
* gst_test_clock_process_id_list:
* @test_clock: #GstTestClock for which to process the pending IDs
- * @pending_list: A #GstTestClockIDList with pending #GstClockIDs
+ * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List
+ * of pending #GstClockIDs
*
- * Processes and releases the pending IDs in #GstTestClockIDList
+ * Processes and releases the pending IDs in the list.
*
* MT safe.
*
*/
guint
gst_test_clock_process_id_list (GstTestClock * test_clock,
- GstTestClockIDList * pending_list)
+ const GList * pending_list)
{
- GList *cur;
+ const GList *cur;
guint result = 0;
g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0);
GST_OBJECT_LOCK (test_clock);
- for (cur = pending_list->cur; cur != NULL; cur = cur->next) {
+ for (cur = pending_list; cur != NULL; cur = cur->next) {
GstClockID pending_id = cur->data;
GstClockEntryContext *ctx =
gst_test_clock_lookup_entry_context (test_clock, pending_id);
/**
* gst_test_clock_id_list_get_latest_time:
- * @pending_list: A #GstTestClockIDList with pending #GstClockIDs
+ * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List
+ * of of pending #GstClockIDs
*
- * Finds the latest time inside the #GstTestClockIDList
+ * Finds the latest time inside the list.
*
* MT safe.
*
* Since: 1.4
*/
GstClockTime
-gst_test_clock_id_list_get_latest_time (GstTestClockIDList * pending_list)
+gst_test_clock_id_list_get_latest_time (const GList * pending_list)
{
- GList *cur;
+ const GList *cur;
GstClockTime result = 0;
- for (cur = pending_list->cur; cur != NULL; cur = cur->next) {
+ for (cur = pending_list; cur != NULL; cur = cur->next) {
GstClockID *pending_id = cur->data;
GstClockTime time = gst_clock_id_get_time (pending_id);
if (time > result)
}
/**
- * gst_test_clock_id_list_free:
- * @pending_list: A #GstTestClockIDList with pending #GstClockIDs
+ * gst_test_clock_crank:
+ * @test_clock: #GstTestClock to crank
+ *
+ * A "crank" consists of three steps:
+ * 1: Wait for a #GstClockID to be registered with the #GstTestClock.
+ * 2: Advance the #GstTestClock to the time the #GstClockID is waiting for.
+ * 3: Release the #GstClockID wait.
+ * A "crank" can be though of as the notion of
+ * manually driving the clock forward to its next logical step.
*
- * Free the supplied #GstTestClockIDList
+ * Return: %TRUE if the crank was successful, %FALSE otherwise.
*
* MT safe.
*
- * Since: 1.4
+ * Since: 1.8
*/
-void
-gst_test_clock_id_list_free (GstTestClockIDList * pending_list)
+gboolean
+gst_test_clock_crank (GstTestClock * test_clock)
{
- GList *cur;
+ GstClockID res, pending;
+ gboolean result;
- for (cur = pending_list->cur; cur != NULL; cur = cur->next) {
- GstClockID *pending_id = cur->data;
- gst_clock_id_unref (pending_id);
+ gst_test_clock_wait_for_next_pending_id (test_clock, &pending);
+ gst_test_clock_set_time (test_clock, gst_clock_id_get_time (pending));
+ res = gst_test_clock_process_next_clock_id (test_clock);
+ if (G_LIKELY (res == pending)) {
+ GST_CAT_DEBUG_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
+ "cranked to time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (gst_clock_get_time (GST_CLOCK (test_clock))));
+ result = TRUE;
+ } else {
+ GST_CAT_WARNING_OBJECT (GST_CAT_TEST_CLOCK, test_clock,
+ "testclock next id != pending (%p != %p)", res, pending);
+ result = FALSE;
}
- g_list_free (pending_list->cur);
- g_free (pending_list);
+ if (G_LIKELY (res != NULL))
+ gst_clock_id_unref (res);
+
+ gst_clock_id_unref (pending);
+
+ return result;
}