[]Struct gstreamer_check::TestClock

pub struct TestClock(_, _);

GstTestClock is an implementation of gst::Clock which has different behaviour compared to gst::SystemClock. Time for gst::SystemClock advances according to the system time, while time for TestClock changes only when TestClock::set_time or TestClock::advance_time are called. TestClock 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 TestClock

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

gst::Clock 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.

TestClock keeps track of these clock notifications. By calling TestClock::wait_for_next_pending_id or TestClock::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 TestClock::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 TestClock 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 TestClock::wait_for_next_pending_id or TestClock::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 TestClock, 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 TestClock

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

Implements

gst::ClockExt, gst::ObjectExt, glib::object::ObjectExt

Methods

impl TestClock[src]

pub fn new() -> TestClock[src]

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

MT safe.

Returns

a TestClock cast to gst::Clock.

pub fn new_with_start_time(start_time: ClockTime) -> TestClock[src]

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

MT safe.

start_time

a gst::ClockTime set to the desired start time of the clock.

Returns

a TestClock cast to gst::Clock.

pub fn advance_time(&self, delta: ClockTimeDiff)[src]

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

MT safe.

delta

a positive gst::ClockTimeDiff to be added to the time of the clock

pub fn crank(&self) -> bool[src]

A "crank" consists of three steps: 1: Wait for a gst::ClockID to be registered with the TestClock. 2: Advance the TestClock to the time the gst::ClockID is waiting for. 3: Release the gst::ClockID wait. A "crank" can be though of as the notion of manually driving the clock forward to its next logical step.

Returns

true if the crank was successful, false otherwise.

MT safe.

pub fn get_next_entry_time(&self) -> ClockTime[src]

Retrieve the requested time for the next pending clock notification.

MT safe.

Returns

a gst::ClockTime set to the time of the next pending clock notification. If no clock notifications have been requested GST_CLOCK_TIME_NONE will be returned.

pub fn peek_id_count(&self) -> u32[src]

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

MT safe.

Returns

the number of pending clock notifications.

pub fn set_time(&self, new_time: ClockTime)[src]

Sets the time of self to the time given by new_time. The time of self is monotonically increasing, therefore providing a new_time which is earlier or equal to the time of the clock as given by gst::ClockExt::get_time is a programming error.

MT safe.

new_time

a gst::ClockTime later than that returned by gst::ClockExt::get_time

pub fn wait_for_pending_id_count(&self, count: u32)[src]

Blocks until at least count clock notifications have been requested from self. There is no timeout for this wait, see the main description of TestClock.

Deprecated

use TestClock::wait_for_multiple_pending_ids instead.

count

the number of pending clock notifications to wait for

pub fn get_property_clock_type(&self) -> ClockType[src]

pub fn set_property_clock_type(&self, clock_type: ClockType)[src]

pub fn get_property_start_time(&self) -> u64[src]

When a TestClock is constructed it will have a certain start time set. If the clock was created using TestClock::new_with_start_time then this property contains the value of the start_time argument. If TestClock::new was called the clock started at time zero, and thus this property contains the value 0.

pub fn connect_property_clock_type_notify<F: Fn(&TestClock) + Send + Sync + 'static>(
    &self,
    f: F
) -> SignalHandlerId
[src]

impl TestClock[src]

pub fn has_id(&self, id: &ClockId) -> bool[src]

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

MT safe.

id

a gst::ClockID clock notification

Returns

true if the clock has been asked to provide the given clock notification, false otherwise.

pub fn peek_next_pending_id(&self) -> Option<ClockId>[src]

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

MT safe.

pending_id

a gst::ClockID clock notification to look for

Returns

true if pending_id is the next clock notification to be triggered, false otherwise.

pub fn process_id_list(&self, pending_list: &[&ClockId]) -> u32[src]

Processes and releases the pending IDs in the list.

MT safe.

pending_list

List of pending GstClockIDs

pub fn process_next_clock_id(&self) -> Option<ClockId>[src]

MT safe.

Returns

a gst::ClockID containing the next pending clock notification.

pub fn wait_for_multiple_pending_ids(&self, count: u32) -> Vec<ClockId>[src]

Blocks until at least count clock notifications have been requested from self. There is no timeout for this wait, see the main description of TestClock.

MT safe.

count

the number of pending clock notifications to wait for

pending_list

Address of a glib::List pointer variable to store the list of pending GstClockIDs that expired, or None

pub fn wait_for_next_pending_id(&self) -> ClockId[src]

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

MT safe.

pending_id

gst::ClockID with information about the pending clock notification

pub fn timed_wait_for_multiple_pending_ids(
    &self,
    count: u32,
    timeout_ms: u32
) -> (bool, Vec<ClockId>)
[src]

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

MT safe.

Feature: v1_16

count

the number of pending clock notifications to wait for

timeout_ms

the timeout in milliseconds

pending_list

Address of a glib::List pointer variable to store the list of pending GstClockIDs that expired, or 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)

Trait Implementations

impl Clone for TestClock

impl Debug for TestClock

impl Default for TestClock[src]

impl Eq for TestClock

impl Hash for TestClock

impl IsA<Clock> for TestClock

impl IsA<Object> for TestClock

impl Ord for TestClock

impl<T: ObjectType> PartialEq<T> for TestClock

impl<T: ObjectType> PartialOrd<T> for TestClock

impl Send for TestClock[src]

impl StaticType for TestClock

impl Sync for TestClock[src]

Auto Trait Implementations

impl RefUnwindSafe for TestClock

impl Unpin for TestClock

impl UnwindSafe for TestClock

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Super, Sub> CanDowncast<Sub> for Super where
    Sub: IsA<Super>,
    Super: IsA<Super>, 
[src]

impl<T> Cast for T where
    T: ObjectType
[src]

impl<O> ClockExt for O where
    O: IsA<Clock>, 
[src]

impl<O> ClockExtManual for O where
    O: IsA<Clock>, 
[src]

impl<T> From<T> for T[src]

impl<O> GObjectExtManualGst for O where
    O: IsA<Object>, 
[src]

impl<O> GstObjectExt for O where
    O: IsA<Object>, 
[src]

impl<O> GstObjectExtManual for O where
    O: IsA<Object>, 
[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> ObjectExt for T where
    T: ObjectType
[src]

impl<'a, T> ToGlibContainerFromSlice<'a, *const GList> for T where
    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>, 
[src]

impl<'a, T> ToGlibContainerFromSlice<'a, *const GPtrArray> for T where
    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>, 
[src]

impl<'a, T> ToGlibContainerFromSlice<'a, *mut GArray> for T where
    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>, 
[src]

impl<'a, T> ToGlibContainerFromSlice<'a, *mut GList> for T where
    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>, 
[src]

impl<'a, T> ToGlibContainerFromSlice<'a, *mut GPtrArray> for T where
    T: GlibPtrDefault + ToGlibPtr<'a, <T as GlibPtrDefault>::GlibType>, 
[src]

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T> ToSendValue for T where
    T: ToValue + SetValue + Send + ?Sized
[src]

impl<T> ToValue for T where
    T: SetValue + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.