GstTestClock

## GstTestClock GstTestClock — Controllable, deterministic clock for GStreamer unit tests |

## Synopsis

    #include <gst/check/gsttestclock.h>

    struct              GstTestClock;
    struct              GstTestClockClass;
    GstClock *          gst_test_clock_new                  (void);
    GstClock *          gst_test_clock_new_with_start_time  (GstClockTime start_time);
    void                gst_test_clock_set_time             (GstTestClock *test_clock,
                                                             GstClockTime new_time);
    void                gst_test_clock_advance_time         (GstTestClock *test_clock,
                                                             GstClockTimeDiff delta);
    guint               gst_test_clock_peek_id_count        (GstTestClock *test_clock);
    gboolean            gst_test_clock_has_id               (GstTestClock *test_clock,
                                                             GstClockID id);
    gboolean            gst_test_clock_peek_next_pending_id (GstTestClock *test_clock,
                                                             GstClockID *pending_id);
    void                gst_test_clock_wait_for_next_pending_id
                                                            (GstTestClock *test_clock,
                                                             GstClockID *pending_id);
    void                gst_test_clock_wait_for_pending_id_count
                                                            (GstTestClock *test_clock,
                                                             guint count);
    GstClockID          gst_test_clock_process_next_clock_id
                                                            (GstTestClock *test_clock);
    GstClockTime        gst_test_clock_get_next_entry_time  (GstTestClock *test_clock);

## Object Hierarchy

      GObject
       +----GInitiallyUnowned
             +----GstObject
                   +----GstClock
                         +----GstTestClock

## Properties

      "start-time"               guint64               : Read / Write / Construct Only

## Description

GstTestClock is an implementation of GstClock which has different behaviour compared to GstSystemClock. Time for GstSystemClock advances according to the system time, while time for GstTestClock changes only when `gst_test_clock_set_time()` or `gst_test_clock_advance_time()` are called. GstTestClock provides unit tests with the possibility to precisely advance the time in a deterministic manner, independent of the system time or any other external factors.

Example 1. Advancing the time of a GstTestClock

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <gst/gst.h>
    #include <gst/check/gsttestclock.h>

    GstClock *clock;
    GstTestClock *test_clock;

    clock = gst_test_clock_new ();
    test_clock = GST_TEST_CLOCK (clock);
    GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
    gst_test_clock_advance_time ( test_clock, 1 * GST_SECOND);
    GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (clock)));
    g_usleep (10 * G_USEC_PER_SEC);
    GST_INFO ("Time: %" GST_TIME_FORMAT, GST_TIME_ARGS (gst_clock_get_time (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)));
    ...

GstClock allows for setting up single shot or periodic clock notifications as well as waiting for these notifications synchronously (using `gst_clock_id_wait()`) or asynchronously (using `gst_clock_id_wait_async()` or `gst_clock_id_wait_async_full()`). This is used by many GStreamer elements, among them GstBaseSrc and GstBaseSink.

GstTestClock keeps track of these clock notifications. By calling `gst_test_clock_wait_for_next_pending_id()` or `gst_test_clock_wait_for_pending_id_count()` a unit tests may wait for the next one or several clock notifications to be requested. Additionally unit tests may release blocked waits in a controlled fashion by calling `gst_test_clock_process_next_clock_id()`. This way a unit test can control the inaccuracy (jitter) of clock notifications, since the test can decide to release blocked waits when the clock time has advanced exactly to, or past, the requested clock notification time.

There are also interfaces for determining if a notification belongs to a GstTestClock or not, as well as getting the number of requested clock notifications so far.

N.B.: When a unit test waits for a certain amount of clock notifications to be requested in `gst_test_clock_wait_for_next_pending_id()` or `gst_test_clock_wait_for_pending_id_count()` then these functions may block for a long time. If they block forever then the expected clock notifications were never requested from GstTestClock, and so the assumptions in the code of the unit test are wrong. The unit test case runner in GstCheck is expected to catch these cases either by the default test case timeout or the one set for the unit test by calling `tcase_set_timeout()`.

The sample code below assumes that the element under test will delay a buffer pushed on the source pad by some latency until it arrives on the sink pad. Moreover it is assumed that the element will at some point call `gst_clock_id_wait()` to synchronously wait for a specific time. The first buffer sent will arrive exactly on time only delayed by the latency. The second buffer will arrive a little late (7ms) due to simulated jitter in the clock notification.

Example 2. Demonstration of how to work with clock notifications and GstTestClock

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    #include <gst/gst.h>
    #include <gst/check/gstcheck.h>
    #include <gst/check/gsttestclock.h>

    GstClockTime latency;
    GstElement *element;
    GstPad *srcpad;
    GstClock *clock;
    GstTestClock *test_clock;
    GstBuffer buf;
    GstClockID pending_id;
    GstClockID processed_id;

    latency = 42 * GST_MSECOND;
    element = create_element (latency, ...);
    srcpad = get_source_pad (element);

    clock = gst_test_clock_new ();
    test_clock = GST_TEST_CLOCK (clock);
    gst_element_set_clock (element, clock);

    GST_INFO ("Set time, create and push the first buffer\n");
    gst_test_clock_set_time (test_clock, 0);
    buf = create_test_buffer (gst_clock_get_time (clock), ...);
    gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);

    GST_INFO ("Block until element is waiting for a clock notification\n");
    gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
    GST_INFO ("Advance to the requested time of the clock notification\n");
    gst_test_clock_advance_time (test_clock, latency);
    GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
    processed_id = gst_test_clock_process_next_clock_id (test_clock);
    g_assert (processed_id == pending_id);
    g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
    gst_clock_id_unref (pending_id);
    gst_clock_id_unref (processed_id);

    GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
    g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
    buf = get_buffer_pushed_by_element (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);

    GST_INFO ("Set time, create and push the second buffer\n");
    gst_test_clock_advance_time (test_clock, 10 * GST_SECOND);
    buf = create_test_buffer (gst_clock_get_time (clock), ...);
    gst_assert_cmpint (gst_pad_push (srcpad, buf), ==, GST_FLOW_OK);

    GST_INFO ("Block until element is waiting for a new clock notification\n");
    (gst_test_clock_wait_for_next_pending_id (test_clock, &pending_id);
    GST_INFO ("Advance past 7ms beyond the requested time of the clock notification\n");
    gst_test_clock_advance_time (test_clock, latency + 7 * GST_MSECOND);
    GST_INFO ("Release the next blocking wait and make sure it is the one from element\n");
    processed_id = gst_test_clock_process_next_clock_id (test_clock);
    g_assert (processed_id == pending_id);
    g_assert_cmpint (GST_CLOCK_ENTRY_STATUS (processed_id), ==, GST_CLOCK_OK);
    gst_clock_id_unref (pending_id);
    gst_clock_id_unref (processed_id);

    GST_INFO ("Validate that element produced an output buffer and check its timestamp\n");
    g_assert_cmpint (get_number_of_output_buffer (...), ==, 1);
    buf = get_buffer_pushed_by_element (element, ...);
    g_assert_cmpint (GST_BUFFER_TIMESTAMP (buf), ==,
        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);
    ...

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 arguments. This will highlight any issues with the unit test code itself.

## Details

### struct GstTestClock

    struct GstTestClock;

A GstTestClock structure which is based on a GstClock along with some private data.

Since 1.2

### struct GstTestClockClass

    struct GstTestClockClass {
      GstClockClass parent_class;
    };

The class of a GstTestClock, which has no virtual methods to override.

GstClockClass `parent_class`; | the parent class structure

Since 1.2

### gst_test_clock_new ()

    GstClock *          gst_test_clock_new                  (void);

Creates a new test clock with its time set to zero.

MT safe.

Returns : | a GstTestClock cast to GstClock. [transfer full]

Since 1.2

### gst_test_clock_new_with_start_time ()

    GstClock *          gst_test_clock_new_with_start_time  (GstClockTime start_time);

Creates a new test clock with its time set to the specified time.

MT safe.

`start_time` : | a GstClockTime set to the desired start time of the clock.
Returns : | a GstTestClock cast to GstClock. [transfer full]

Since 1.2

### gst_test_clock_set_time ()

    void                gst_test_clock_set_time             (GstTestClock *test_clock,
                                                             GstClockTime new_time);

Sets the time of `test_clock` to the time given by `new_time`. The time of `test_clock` is monotonically increasing, therefore providing a `new_time` which is earlier or equal to the time of the clock as given by `gst_clock_get_time()` is a programming error.

MT safe.

`test_clock` : | a GstTestClock of which to set the time
`new_time` : | a GstClockTime later than that returned by `gst_clock_get_time()`

Since 1.2

### gst_test_clock_advance_time ()

    void                gst_test_clock_advance_time         (GstTestClock *test_clock,
                                                             GstClockTimeDiff delta);

Advances the time of the `test_clock` by the amount given by `delta`. The time of `test_clock` is monotonically increasing, therefore providing a `delta` which is negative or zero is a programming error.

MT safe.

`test_clock` : | a GstTestClock for which to increase the time
`delta` : | a positive GstClockTimeDiff to be added to the time of the clock

Since 1.2

### gst_test_clock_peek_id_count ()

    guint               gst_test_clock_peek_id_count        (GstTestClock *test_clock);

Determine the number of pending clock notifications that have been requested from the `test_clock`.

MT safe.

`test_clock` : | a GstTestClock for which to count notifications
Returns : | the number of pending clock notifications.

Since 1.2

### gst_test_clock_has_id ()

    gboolean            gst_test_clock_has_id               (GstTestClock *test_clock,
                                                             GstClockID id);

Checks whether `test_clock` was requested to provide the clock notification given by `id`.

MT safe.

`test_clock` : | a GstTestClock to ask if it provided the notification
`id` : | a GstClockID clock notification. [transfer none]
Returns : | `TRUE` if the clock has been asked to provide the given clock notification, `FALSE` otherwise.

Since 1.2

### gst_test_clock_peek_next_pending_id ()

    gboolean            gst_test_clock_peek_next_pending_id (GstTestClock *test_clock,
                                                             GstClockID *pending_id);

Determines if the `pending_id` is the next clock notification scheduled to be triggered given the current time of the `test_clock`.

MT safe.

Return: `TRUE` if `pending_id` is the next clock notification to be triggered, `FALSE` otherwise.

`test_clock` : | a GstTestClock to check the clock notifications for
`pending_id` : | a GstClockID clock notification to look for. [allow-none][out][transfer full]

Since 1.2

### gst_test_clock_wait_for_next_pending_id ()

    void                gst_test_clock_wait_for_next_pending_id
                                                            (GstTestClock *test_clock,
                                                             GstClockID *pending_id);

Waits until a clock notification is requested from `test_clock`. There is no timeout for this wait, see the main description of GstTestClock. A reference to the pending clock notification is stored in `pending_id`.

MT safe.

`test_clock` : | GstTestClock for which to get the pending clock notification
`pending_id` : | GstClockID with information about the pending clock notification. [allow-none][out][transfer full]

Since 1.2

### gst_test_clock_wait_for_pending_id_count ()

    void                gst_test_clock_wait_for_pending_id_count
                                                            (GstTestClock *test_clock,
                                                             guint count);

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 GstTestClock.

MT safe.

`test_clock` : | GstTestClock for which to await having enough pending clock
`count` : | the number of pending clock notifications to wait for

Since 1.2

### gst_test_clock_process_next_clock_id ()

    GstClockID          gst_test_clock_process_next_clock_id
                                                            (GstTestClock *test_clock);

MT safe.

`test_clock` : | a GstTestClock for which to retrive the next pending clock notification
Returns : | a GstClockID containing the next pending clock notification. [transfer full]

Since 1.2

### gst_test_clock_get_next_entry_time ()

    GstClockTime        gst_test_clock_get_next_entry_time  (GstTestClock *test_clock);

Retrieve the requested time for the next pending clock notification.

MT safe.

`test_clock` : | a GstTestClock to fetch the next clock notification time for
Returns : | a GstClockTime set to the time of the next pending clock notification. If no clock notifications have been requested `GST_CLOCK_TIME_NONE` will be returned.

Since 1.2

## Property Details

### The `"start-time"` property

      "start-time"               guint64               : Read / Write / Construct Only

When a GstTestClock is constructed it will have a certain start time set. If the clock was created using `gst_test_clock_new_with_start_time()` then this property contains the value of the `start_time` argument. If `gst_test_clock_new()` was called the clock started at time zero, and thus this property contains the value 0.

Default value: 0

## See Also

GstSystemClock, GstClock