GstTestClock: GStreamer Library Reference Manual

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

## Functions

GstClock * | gst_test_clock_new ()
GstClock * | gst_test_clock_new_with_start_time ()
void | gst_test_clock_set_time ()
void | gst_test_clock_advance_time ()
guint | gst_test_clock_peek_id_count ()
gboolean | gst_test_clock_has_id ()
gboolean | gst_test_clock_peek_next_pending_id ()
void | gst_test_clock_wait_for_next_pending_id ()
void | gst_test_clock_wait_for_pending_id_count ()
GstClockID | gst_test_clock_process_next_clock_id ()
GstClockTime | gst_test_clock_get_next_entry_time ()
void | gst_test_clock_wait_for_multiple_pending_ids ()
GstClockTime | gst_test_clock_id_list_get_latest_time ()
gboolean | gst_test_clock_timed_wait_for_multiple_pending_ids ()
guint | gst_test_clock_process_id_list ()
gboolean | gst_test_clock_crank ()

## Properties

GstClockType | clock-type | Read / Write
guint64 | start-time | Read / Write / Construct Only

## Types and Values

struct | GstTestClock
struct | GstTestClockClass

## Object Hierarchy

        GObject
        ╰── GInitiallyUnowned
            ╰── GstObject
                ╰── GstClock
                    ╰── GstTestClock

## Includes

    #include <gst/check/check.h>

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

#### 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()`). 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_multiple_pending_ids()` 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_multiple_pending_ids()` 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.

#### 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));

    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));
    ...

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.

## Functions

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

#### Parameters

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.

#### Parameters

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.

#### Parameters

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.

#### Parameters

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.

#### Parameters

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.

#### Parameters

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.

#### Parameters

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);

`gst_test_clock_wait_for_pending_id_count` is deprecated and should not be used in newly-written code.

use `gst_test_clock_wait_for_multiple_pending_ids()` instead.

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.

#### Parameters

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.

#### Parameters

test_clock | a GstTestClock for which to retrieve 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.

#### Parameters

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

### gst_test_clock_wait_for_multiple_pending_ids ()

    void
    gst_test_clock_wait_for_multiple_pending_ids
                                   (GstTestClock *test_clock,
                                    guint count,
                                    GList **pending_list);

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.

#### Parameters

test_clock | GstTestClock for which to await having enough pending clock |
count | the number of pending clock notifications to wait for |
pending_list | Address of a GList pointer variable to store the list of pending GstClockIDs that expired, or `NULL`. | [out][element-type Gst.ClockID][transfer full][allow-none]

Since: 1.4

### gst_test_clock_id_list_get_latest_time ()

    GstClockTime
    gst_test_clock_id_list_get_latest_time
                                   (const GList *pending_list);

Finds the latest time inside the list.

MT safe.

#### Parameters

pending_list | List of of pending GstClockIDs. | [element-type Gst.ClockID][transfer none][allow-none]

Since: 1.4

### gst_test_clock_timed_wait_for_multiple_pending_ids ()

    gboolean
    gst_test_clock_timed_wait_for_multiple_pending_ids
                                   (GstTestClock *test_clock,
                                    guint count,
                                    guint timeout_ms,
                                    GList **pending_list);

Blocks until at least `count` clock notifications have been requested from `test_clock` , or the timeout expires.

MT safe.

#### Parameters

test_clock | GstTestClock for which to await having enough pending clock |
count | the number of pending clock notifications to wait for |
timeout_ms | the timeout in milliseconds |
pending_list | Address of a GList pointer variable to store the list of pending GstClockIDs that expired, or `NULL`. | [out][element-type Gst.ClockID][transfer full][allow-none]

#### Returns

a `gboolean` `TRUE` if the waits have been registered, `FALSE` if not. (Could be that it timed out waiting or that more waits than waits was found)

Since: 1.16

### gst_test_clock_process_id_list ()

    guint
    gst_test_clock_process_id_list (GstTestClock *test_clock,
                                    const GList *pending_list);

Processes and releases the pending IDs in the list.

MT safe.

#### Parameters

test_clock | GstTestClock for which to process the pending IDs |
pending_list | List of pending GstClockIDs. | [element-type Gst.ClockID][transfer none][allow-none]

Since: 1.4

### gst_test_clock_crank ()

    gboolean
    gst_test_clock_crank (GstTestClock *test_clock);

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.

Return: `TRUE` if the crank was successful, `FALSE` otherwise.

MT safe.

#### Parameters

test_clock | GstTestClock to crank |

Since: 1.8

## Types and Values

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

#### Members

Since: 1.2

## Property Details

### The `“clock-type”` property

      “clock-type”               GstClockType

The kind of clock implementation to be reported by this clock.

Flags: Read / Write

Default value: GST_CLOCK_TYPE_MONOTONIC

### The `“start-time”` property

      “start-time”               guint64

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.

Flags: Read / Write / Construct Only

Default value: 0

## See Also

GstSystemClock, GstClock