GstTestClock

GstTestClock — Controllable, deterministic clock for GStreamer unit tests

Functions

Properties

guint64 start-time Read / Write / Construct Only

Types and Values

Object Hierarchy

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

Includes

#include <gst/check/gsttestclock.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.

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.

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

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

 

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

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

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

GstClockClass parent_class;

the parent class structure

 

Since 1.2

Property Details

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