Skip to main content

gstreamer_check/
harness.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, ops, path, ptr};
4
5use glib::translate::*;
6use gst::prelude::*;
7
8use crate::{TestClock, ffi};
9
10/// [`Harness`][crate::Harness] is meant to make writing unit test for GStreamer much easier.
11/// It can be thought of as a way of treating a [`gst::Element`][crate::gst::Element] as a black box,
12/// deterministically feeding it data, and controlling what data it outputs.
13///
14/// The basic structure of [`Harness`][crate::Harness] is two "floating" `GstPads` that connect
15/// to the harnessed [`gst::Element`][crate::gst::Element] src and sink `GstPads` like so:
16///
17///
18///
19/// **⚠️ The following code is in C ⚠️**
20///
21/// ```C
22///   #include <gst/gst.h>
23///   #include <gst/check/gstharness.h>
24///   GstHarness *h;
25///   GstBuffer *in_buf;
26///   GstBuffer *out_buf;
27///
28///   // attach the harness to the src and sink pad of GstQueue
29///   h = gst_harness_new ("queue");
30///
31///   // we must specify a caps before pushing buffers
32///   gst_harness_set_src_caps_str (h, "mycaps");
33///
34///   // create a buffer of size 42
35///   in_buf = gst_harness_create_buffer (h, 42);
36///
37///   // push the buffer into the queue
38///   gst_harness_push (h, in_buf);
39///
40///   // pull the buffer from the queue
41///   out_buf = gst_harness_pull (h);
42///
43///   // validate the buffer in is the same as buffer out
44///   fail_unless (in_buf == out_buf);
45///
46///   // cleanup
47///   gst_buffer_unref (out_buf);
48///   gst_harness_teardown (h);
49///
50///   ]|
51///
52/// Another main feature of the #GstHarness is its integration with the
53/// #GstTestClock. Operating the #GstTestClock can be very challenging, but
54/// #GstHarness simplifies some of the most desired actions a lot, like wanting
55/// to manually advance the clock while at the same time releasing a #GstClockID
56/// that is waiting, with functions like gst_harness_crank_single_clock_wait().
57///
58/// #GstHarness also supports sub-harnesses, as a way of generating and
59/// validating data. A sub-harness is another #GstHarness that is managed by
60/// the "parent" harness, and can either be created by using the standard
61/// gst_harness_new type functions directly on the (GstHarness *)->src_harness,
62/// or using the much more convenient gst_harness_add_src() or
63/// gst_harness_add_sink_parse(). If you have a decoder-element you want to test,
64/// (like vp8dec) it can be very useful to add a src-harness with both a
65/// src-element (videotestsrc) and an encoder (vp8enc) to feed the decoder data
66/// with different configurations, by simply doing:
67///
68/// |[<!-- language="C" -->
69///   GstHarness * h = gst_harness_new ("vp8dec");
70///   gst_harness_add_src_parse (h, "videotestsrc is-live=1 ! vp8enc", TRUE);
71/// ```
72///
73/// and then feeding it data with:
74///
75///
76///
77/// **⚠️ The following code is in C ⚠️**
78///
79/// ```C
80/// gst_harness_push_from_src (h);
81/// ```
82#[derive(Debug)]
83#[doc(alias = "GstHarness")]
84#[repr(transparent)]
85pub struct Harness(ptr::NonNull<ffi::GstHarness>);
86
87impl Drop for Harness {
88    #[inline]
89    fn drop(&mut self) {
90        unsafe {
91            ffi::gst_harness_teardown(self.0.as_ptr());
92        }
93    }
94}
95
96unsafe impl Send for Harness {}
97unsafe impl Sync for Harness {}
98
99impl Harness {
100    /// Adds a [`gst::Element`][crate::gst::Element] to an empty [`Harness`][crate::Harness]
101    ///
102    /// MT safe.
103    /// ## `element`
104    /// a [`gst::Element`][crate::gst::Element] to add to the harness (transfer none)
105    /// ## `hsrc`
106    /// a [`gst::StaticPadTemplate`][crate::gst::StaticPadTemplate] describing the harness srcpad.
107    /// [`None`] will not create a harness srcpad.
108    /// ## `element_sinkpad_name`
109    /// a `gchar` with the name of the element
110    /// sinkpad that is then linked to the harness srcpad. Can be a static or request
111    /// or a sometimes pad that has been added. [`None`] will not get/request a sinkpad
112    /// from the element. (Like if the element is a src.)
113    /// ## `hsink`
114    /// a [`gst::StaticPadTemplate`][crate::gst::StaticPadTemplate] describing the harness sinkpad.
115    /// [`None`] will not create a harness sinkpad.
116    /// ## `element_srcpad_name`
117    /// a `gchar` with the name of the element
118    /// srcpad that is then linked to the harness sinkpad, similar to the
119    /// `element_sinkpad_name`.
120    #[doc(alias = "gst_harness_add_element_full")]
121    pub fn add_element_full<P: IsA<gst::Element>>(
122        &mut self,
123        element: &P,
124        hsrc: Option<&gst::StaticPadTemplate>,
125        element_sinkpad_name: Option<&str>,
126        hsink: Option<&gst::StaticPadTemplate>,
127        element_srcpad_name: Option<&str>,
128    ) {
129        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
130        let element_srcpad_name = element_srcpad_name.to_glib_none();
131        unsafe {
132            ffi::gst_harness_add_element_full(
133                self.0.as_ptr(),
134                element.as_ref().to_glib_none().0,
135                hsrc.to_glib_none().0 as *mut _,
136                element_sinkpad_name.0,
137                hsink.to_glib_none().0 as *mut _,
138                element_srcpad_name.0,
139            );
140        }
141    }
142
143    /// Links the specified [`gst::Pad`][crate::gst::Pad] the [`Harness`][crate::Harness] srcpad.
144    ///
145    /// MT safe.
146    /// ## `sinkpad`
147    /// a [`gst::Pad`][crate::gst::Pad] to link to the harness srcpad
148    #[doc(alias = "gst_harness_add_element_sink_pad")]
149    pub fn add_element_sink_pad<P: IsA<gst::Pad>>(&mut self, sinkpad: &P) {
150        unsafe {
151            ffi::gst_harness_add_element_sink_pad(
152                self.0.as_ptr(),
153                sinkpad.as_ref().to_glib_none().0,
154            );
155        }
156    }
157
158    /// Links the specified [`gst::Pad`][crate::gst::Pad] the [`Harness`][crate::Harness] sinkpad. This can be useful if
159    /// perhaps the srcpad did not exist at the time of creating the harness,
160    /// like a demuxer that provides a sometimes-pad after receiving data.
161    ///
162    /// MT safe.
163    /// ## `srcpad`
164    /// a [`gst::Pad`][crate::gst::Pad] to link to the harness sinkpad
165    #[doc(alias = "gst_harness_add_element_src_pad")]
166    pub fn add_element_src_pad<P: IsA<gst::Pad>>(&mut self, srcpad: &P) {
167        unsafe {
168            ffi::gst_harness_add_element_src_pad(self.0.as_ptr(), srcpad.as_ref().to_glib_none().0);
169        }
170    }
171
172    /// Parses the `launchline` and puts that in a [`gst::Bin`][crate::gst::Bin],
173    /// and then attches the supplied [`Harness`][crate::Harness] to the bin.
174    ///
175    /// MT safe.
176    /// ## `launchline`
177    /// a `gchar` describing a gst-launch type line
178    #[doc(alias = "gst_harness_add_parse")]
179    pub fn add_parse(&mut self, launchline: &str) {
180        unsafe {
181            ffi::gst_harness_add_parse(self.0.as_ptr(), launchline.to_glib_none().0);
182        }
183    }
184
185    /// A convenience function to allows you to call gst_pad_add_probe on a
186    /// [`gst::Pad`][crate::gst::Pad] of a [`gst::Element`][crate::gst::Element] that are residing inside the [`Harness`][crate::Harness],
187    /// by using normal gst_pad_add_probe syntax
188    ///
189    /// MT safe.
190    /// ## `element_name`
191    /// a `gchar` with a [`gst::ElementFactory`][crate::gst::ElementFactory] name
192    /// ## `pad_name`
193    /// a `gchar` with the name of the pad to attach the probe to
194    /// ## `mask`
195    /// a [`gst::PadProbeType`][crate::gst::PadProbeType] (see gst_pad_add_probe)
196    /// ## `callback`
197    /// a `GstPadProbeCallback` (see gst_pad_add_probe)
198    /// ## `destroy_data`
199    /// a `GDestroyNotify` (see gst_pad_add_probe)
200    pub fn add_probe<F>(
201        &mut self,
202        element_name: &str,
203        pad_name: &str,
204        mask: gst::PadProbeType,
205        func: F,
206    ) where
207        F: Fn(&gst::Pad, &mut gst::PadProbeInfo) -> gst::PadProbeReturn + Send + Sync + 'static,
208    {
209        // Reimplementation of the C code so we don't have to duplicate all the callback code
210
211        let element = self.find_element(element_name).expect("Element not found");
212        let pad = element.static_pad(pad_name).expect("Pad not found");
213        pad.add_probe(mask, func);
214    }
215
216    /// Add api with params as one of the supported metadata API to propose when
217    /// receiving an allocation query.
218    ///
219    /// MT safe.
220    /// ## `api`
221    /// a metadata API
222    /// ## `params`
223    /// API specific parameters
224    #[cfg(feature = "v1_16")]
225    #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
226    #[doc(alias = "gst_harness_add_propose_allocation_meta")]
227    pub fn add_propose_allocation_meta(
228        &mut self,
229        api: glib::types::Type,
230        params: Option<&gst::StructureRef>,
231    ) {
232        unsafe {
233            let params = params.map(|p| p.as_ptr()).unwrap_or(ptr::null_mut());
234            ffi::gst_harness_add_propose_allocation_meta(self.0.as_ptr(), api.into_glib(), params);
235        }
236    }
237
238    /// Similar to gst_harness_add_sink_harness, this is a convenience to
239    /// directly create a sink-harness using the `sink_element_name` name specified.
240    ///
241    /// MT safe.
242    /// ## `sink_element_name`
243    /// a `gchar` with the name of a [`gst::Element`][crate::gst::Element]
244    #[doc(alias = "gst_harness_add_sink")]
245    pub fn add_sink(&mut self, sink_element_name: &str) {
246        unsafe {
247            ffi::gst_harness_add_sink(self.0.as_ptr(), sink_element_name.to_glib_none().0);
248        }
249    }
250
251    /// Similar to gst_harness_add_src, this allows you to send the data coming out
252    /// of your harnessed [`gst::Element`][crate::gst::Element] to a sink-element, allowing to test different
253    /// responses the element output might create in sink elements. An example might
254    /// be an existing sink providing some analytical data on the input it receives that
255    /// can be useful to your testing. If the goal is to test a sink-element itself,
256    /// this is better achieved using gst_harness_new directly on the sink.
257    ///
258    /// If a sink-harness already exists it will be replaced.
259    ///
260    /// MT safe.
261    /// ## `sink_harness`
262    /// a [`Harness`][crate::Harness] to be added as a sink-harness.
263    #[doc(alias = "gst_harness_add_sink_harness")]
264    pub fn add_sink_harness(&mut self, sink_harness: Harness) {
265        unsafe {
266            let sink_harness = mem::ManuallyDrop::new(sink_harness);
267            ffi::gst_harness_add_sink_harness(self.0.as_ptr(), sink_harness.0.as_ptr());
268        }
269    }
270
271    /// Similar to gst_harness_add_sink, this allows you to specify a launch-line
272    /// instead of just an element name. See gst_harness_add_src_parse for details.
273    ///
274    /// MT safe.
275    /// ## `launchline`
276    /// a `gchar` with the name of a [`gst::Element`][crate::gst::Element]
277    #[doc(alias = "gst_harness_add_sink_parse")]
278    pub fn add_sink_parse(&mut self, launchline: &str) {
279        unsafe {
280            ffi::gst_harness_add_sink_parse(self.0.as_ptr(), launchline.to_glib_none().0);
281        }
282    }
283
284    /// Similar to gst_harness_add_src_harness, this is a convenience to
285    /// directly create a src-harness using the `src_element_name` name specified.
286    ///
287    /// MT safe.
288    /// ## `src_element_name`
289    /// a `gchar` with the name of a [`gst::Element`][crate::gst::Element]
290    /// ## `has_clock_wait`
291    /// a `gboolean` specifying if the [`gst::Element`][crate::gst::Element] uses
292    /// gst_clock_wait_id internally.
293    #[doc(alias = "gst_harness_add_src")]
294    pub fn add_src(&mut self, src_element_name: &str, has_clock_wait: bool) {
295        unsafe {
296            ffi::gst_harness_add_src(
297                self.0.as_ptr(),
298                src_element_name.to_glib_none().0,
299                has_clock_wait.into_glib(),
300            );
301        }
302    }
303
304    /// A src-harness is a great way of providing the [`Harness`][crate::Harness] with data.
305    /// By adding a src-type [`gst::Element`][crate::gst::Element], it is then easy to use functions like
306    /// gst_harness_push_from_src or gst_harness_src_crank_and_push_many
307    /// to provide your harnessed element with input. The `has_clock_wait` variable
308    /// is a great way to control you src-element with, in that you can have it
309    /// produce a buffer for you by simply cranking the clock, and not have it
310    /// spin out of control producing buffers as fast as possible.
311    ///
312    /// If a src-harness already exists it will be replaced.
313    ///
314    /// MT safe.
315    /// ## `src_harness`
316    /// a [`Harness`][crate::Harness] to be added as a src-harness.
317    /// ## `has_clock_wait`
318    /// a `gboolean` specifying if the [`gst::Element`][crate::gst::Element] uses
319    /// gst_clock_wait_id internally.
320    #[doc(alias = "gst_harness_add_src_harness")]
321    pub fn add_src_harness(&mut self, src_harness: Harness, has_clock_wait: bool) {
322        unsafe {
323            let src_harness = mem::ManuallyDrop::new(src_harness);
324            ffi::gst_harness_add_src_harness(
325                self.0.as_ptr(),
326                src_harness.0.as_ptr(),
327                has_clock_wait.into_glib(),
328            );
329        }
330    }
331
332    /// Similar to gst_harness_add_src, this allows you to specify a launch-line,
333    /// which can be useful for both having more then one [`gst::Element`][crate::gst::Element] acting as your
334    /// src (Like a src producing raw buffers, and then an encoder, providing encoded
335    /// data), but also by allowing you to set properties like "is-live" directly on
336    /// the elements.
337    ///
338    /// MT safe.
339    /// ## `launchline`
340    /// a `gchar` describing a gst-launch type line
341    /// ## `has_clock_wait`
342    /// a `gboolean` specifying if the [`gst::Element`][crate::gst::Element] uses
343    /// gst_clock_wait_id internally.
344    #[doc(alias = "gst_harness_add_src_parse")]
345    pub fn add_src_parse(&mut self, launchline: &str, has_clock_wait: bool) {
346        unsafe {
347            ffi::gst_harness_add_src_parse(
348                self.0.as_ptr(),
349                launchline.to_glib_none().0,
350                has_clock_wait.into_glib(),
351            );
352        }
353    }
354
355    /// The number of `GstBuffers` currently in the [`Harness`][crate::Harness] sinkpad `GAsyncQueue`
356    ///
357    /// MT safe.
358    ///
359    /// # Returns
360    ///
361    /// a `guint` number of buffers in the queue
362    #[doc(alias = "gst_harness_buffers_in_queue")]
363    pub fn buffers_in_queue(&self) -> u32 {
364        unsafe { ffi::gst_harness_buffers_in_queue(self.0.as_ptr()) }
365    }
366
367    /// The total number of `GstBuffers` that has arrived on the [`Harness`][crate::Harness] sinkpad.
368    /// This number includes buffers that have been dropped as well as buffers
369    /// that have already been pulled out.
370    ///
371    /// MT safe.
372    ///
373    /// # Returns
374    ///
375    /// a `guint` number of buffers received
376    #[doc(alias = "gst_harness_buffers_received")]
377    pub fn buffers_received(&self) -> u32 {
378        unsafe { ffi::gst_harness_buffers_received(self.0.as_ptr()) }
379    }
380
381    /// Similar to [`crank_single_clock_wait()`][Self::crank_single_clock_wait()], this is the function to use
382    /// if your harnessed element(s) are using more then one gst_clock_id_wait.
383    /// Failing to do so can (and will) make it racy which `GstClockID` you actually
384    /// are releasing, where as this function will process all the waits at the
385    /// same time, ensuring that one thread can't register another wait before
386    /// both are released.
387    ///
388    /// MT safe.
389    /// ## `waits`
390    /// a `guint` describing the number of `GstClockIDs` to crank
391    ///
392    /// # Returns
393    ///
394    /// a `gboolean` [`true`] if the "crank" was successful, [`false`] if not.
395    #[doc(alias = "gst_harness_crank_multiple_clock_waits")]
396    pub fn crank_multiple_clock_waits(&mut self, waits: u32) -> Result<(), glib::BoolError> {
397        unsafe {
398            glib::result_from_gboolean!(
399                ffi::gst_harness_crank_multiple_clock_waits(self.0.as_ptr(), waits),
400                "Failed to crank multiple clock waits",
401            )
402        }
403    }
404
405    /// A "crank" consists of three steps:
406    /// 1: Wait for a `GstClockID` to be registered with the [`TestClock`][crate::TestClock].
407    /// 2: Advance the [`TestClock`][crate::TestClock] to the time the `GstClockID` is waiting for.
408    /// 3: Release the `GstClockID` wait.
409    /// Together, this provides an easy way to not have to think about the details
410    /// around clocks and time, but still being able to write deterministic tests
411    /// that are dependent on this. A "crank" can be though of as the notion of
412    /// manually driving the clock forward to its next logical step.
413    ///
414    /// MT safe.
415    ///
416    /// # Returns
417    ///
418    /// a `gboolean` [`true`] if the "crank" was successful, [`false`] if not.
419    #[doc(alias = "gst_harness_crank_single_clock_wait")]
420    pub fn crank_single_clock_wait(&mut self) -> Result<(), glib::BoolError> {
421        unsafe {
422            glib::result_from_gboolean!(
423                ffi::gst_harness_crank_single_clock_wait(self.0.as_ptr()),
424                "Failed to crank single clock wait",
425            )
426        }
427    }
428
429    /// Allocates a buffer using a [`gst::BufferPool`][crate::gst::BufferPool] if present, or else using the
430    /// configured [`gst::Allocator`][crate::gst::Allocator] and [`gst::AllocationParams`][crate::gst::AllocationParams]
431    ///
432    /// MT safe.
433    /// ## `size`
434    /// a `gsize` specifying the size of the buffer
435    ///
436    /// # Returns
437    ///
438    /// a [`gst::Buffer`][crate::gst::Buffer] of size `size`
439    #[doc(alias = "gst_harness_create_buffer")]
440    pub fn create_buffer(&mut self, size: usize) -> Result<gst::Buffer, glib::BoolError> {
441        unsafe {
442            Option::<_>::from_glib_full(ffi::gst_harness_create_buffer(self.0.as_ptr(), size))
443                .ok_or_else(|| glib::bool_error!("Failed to create new buffer"))
444        }
445    }
446
447    /// Allows you to dump the `GstBuffers` the [`Harness`][crate::Harness] sinkpad `GAsyncQueue`
448    /// to a file.
449    ///
450    /// MT safe.
451    /// ## `filename`
452    /// a `gchar` with a the name of a file
453    #[doc(alias = "gst_harness_dump_to_file")]
454    pub fn dump_to_file(&mut self, filename: impl AsRef<path::Path>) {
455        let filename = filename.as_ref();
456        unsafe {
457            ffi::gst_harness_dump_to_file(self.0.as_ptr(), filename.to_glib_none().0);
458        }
459    }
460
461    /// The number of `GstEvents` currently in the [`Harness`][crate::Harness] sinkpad `GAsyncQueue`
462    ///
463    /// MT safe.
464    ///
465    /// # Returns
466    ///
467    /// a `guint` number of events in the queue
468    #[doc(alias = "gst_harness_events_in_queue")]
469    pub fn events_in_queue(&self) -> u32 {
470        unsafe { ffi::gst_harness_events_in_queue(self.0.as_ptr()) }
471    }
472
473    /// The total number of `GstEvents` that has arrived on the [`Harness`][crate::Harness] sinkpad
474    /// This number includes events handled by the harness as well as events
475    /// that have already been pulled out.
476    ///
477    /// MT safe.
478    ///
479    /// # Returns
480    ///
481    /// a `guint` number of events received
482    #[doc(alias = "gst_harness_events_received")]
483    pub fn events_received(&self) -> u32 {
484        unsafe { ffi::gst_harness_events_received(self.0.as_ptr()) }
485    }
486
487    /// Most useful in conjunction with gst_harness_new_parse, this will scan the
488    /// `GstElements` inside the [`Harness`][crate::Harness], and check if any of them matches
489    /// `element_name`. Typical usecase being that you need to access one of the
490    /// harnessed elements for properties and/or signals.
491    ///
492    /// MT safe.
493    /// ## `element_name`
494    /// a `gchar` with a [`gst::ElementFactory`][crate::gst::ElementFactory] name
495    ///
496    /// # Returns
497    ///
498    /// a [`gst::Element`][crate::gst::Element] or [`None`] if not found
499    #[doc(alias = "gst_harness_find_element")]
500    pub fn find_element(&mut self, element_name: &str) -> Option<gst::Element> {
501        unsafe {
502            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
503            let ptr = ffi::gst_harness_find_element(self.0.as_ptr(), element_name.to_glib_none().0);
504
505            if ptr.is_null() {
506                return None;
507            }
508
509            // Clear floating flag if it is set
510            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
511                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
512            }
513
514            from_glib_full(ptr)
515        }
516    }
517
518    //pub fn get(&mut self, element_name: &str, first_property_name: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) {
519    //    unsafe { TODO: call ffi::gst_harness_get() }
520    //}
521
522    //pub fn get_allocator(&mut self, allocator: /*Ignored*/gst::Allocator, params: /*Ignored*/gst::AllocationParams) {
523    //    unsafe { TODO: call ffi::gst_harness_get_allocator() }
524    //}
525
526    /// Get the timestamp of the last [`gst::Buffer`][crate::gst::Buffer] pushed on the [`Harness`][crate::Harness] srcpad,
527    /// typically with gst_harness_push or gst_harness_push_from_src.
528    ///
529    /// MT safe.
530    ///
531    /// # Returns
532    ///
533    /// a `GstClockTime` with the timestamp or `GST_CLOCK_TIME_NONE` if no
534    /// [`gst::Buffer`][crate::gst::Buffer] has been pushed on the [`Harness`][crate::Harness] srcpad
535    #[doc(alias = "get_last_pushed_timestamp")]
536    #[doc(alias = "gst_harness_get_last_pushed_timestamp")]
537    pub fn last_pushed_timestamp(&self) -> Option<gst::ClockTime> {
538        unsafe { from_glib(ffi::gst_harness_get_last_pushed_timestamp(self.0.as_ptr())) }
539    }
540
541    /// Get the [`TestClock`][crate::TestClock]. Useful if specific operations on the testclock is
542    /// needed.
543    ///
544    /// MT safe.
545    ///
546    /// # Returns
547    ///
548    /// a [`TestClock`][crate::TestClock], or [`None`] if the testclock is not
549    /// present.
550    #[doc(alias = "get_testclock")]
551    #[doc(alias = "gst_harness_get_testclock")]
552    pub fn testclock(&self) -> Option<TestClock> {
553        unsafe { from_glib_full(ffi::gst_harness_get_testclock(self.0.as_ptr())) }
554    }
555
556    /// This will set the harnessed [`gst::Element`][crate::gst::Element] to [`gst::State::Playing`][crate::gst::State::Playing].
557    /// `GstElements` without a sink-[`gst::Pad`][crate::gst::Pad] and with the [`gst::ElementFlags::SOURCE`][crate::gst::ElementFlags::SOURCE]
558    /// flag set is considered a src [`gst::Element`][crate::gst::Element]
559    /// Non-src `GstElements` (like sinks and filters) are automatically set to
560    /// playing by the [`Harness`][crate::Harness], but src `GstElements` are not to avoid them
561    /// starting to produce buffers.
562    /// Hence, for src [`gst::Element`][crate::gst::Element] you must call [`play()`][Self::play()] explicitly.
563    ///
564    /// MT safe.
565    #[doc(alias = "gst_harness_play")]
566    pub fn play(&mut self) {
567        unsafe {
568            ffi::gst_harness_play(self.0.as_ptr());
569        }
570    }
571
572    /// Pulls a [`gst::Buffer`][crate::gst::Buffer] from the `GAsyncQueue` on the [`Harness`][crate::Harness] sinkpad. The pull
573    /// will timeout in 60 seconds. This is the standard way of getting a buffer
574    /// from a harnessed [`gst::Element`][crate::gst::Element].
575    ///
576    /// MT safe.
577    ///
578    /// # Returns
579    ///
580    /// a [`gst::Buffer`][crate::gst::Buffer] or [`None`] if timed out.
581    #[doc(alias = "gst_harness_pull")]
582    pub fn pull(&mut self) -> Result<gst::Buffer, glib::BoolError> {
583        unsafe {
584            Option::<_>::from_glib_full(ffi::gst_harness_pull(self.0.as_ptr()))
585                .ok_or_else(|| glib::bool_error!("Failed to pull buffer"))
586        }
587    }
588
589    /// Pulls a [`gst::Buffer`][crate::gst::Buffer] from the `GAsyncQueue` on the [`Harness`][crate::Harness] sinkpad. The pull
590    /// will block until an EOS event is received, or timeout in 60 seconds.
591    /// MT safe.
592    ///
593    /// # Returns
594    ///
595    /// [`true`] on success, [`false`] on timeout.
596    ///
597    /// ## `buf`
598    /// A [`gst::Buffer`][crate::gst::Buffer], or [`None`] if EOS or timeout occures
599    ///  first.
600    #[cfg(feature = "v1_18")]
601    #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
602    #[doc(alias = "gst_harness_pull_until_eos")]
603    pub fn pull_until_eos(&mut self) -> Result<Option<gst::Buffer>, glib::BoolError> {
604        unsafe {
605            let mut buffer = ptr::null_mut();
606            let res = ffi::gst_harness_pull_until_eos(self.0.as_ptr(), &mut buffer);
607            if from_glib(res) {
608                Ok(from_glib_full(buffer))
609            } else {
610                Err(glib::bool_error!("Failed to pull buffer or EOS"))
611            }
612        }
613    }
614
615    /// Pulls an [`gst::Event`][crate::gst::Event] from the `GAsyncQueue` on the [`Harness`][crate::Harness] sinkpad.
616    /// Timeouts after 60 seconds similar to gst_harness_pull.
617    ///
618    /// MT safe.
619    ///
620    /// # Returns
621    ///
622    /// a [`gst::Event`][crate::gst::Event] or [`None`] if timed out.
623    #[doc(alias = "gst_harness_pull_event")]
624    pub fn pull_event(&mut self) -> Result<gst::Event, glib::BoolError> {
625        unsafe {
626            Option::<_>::from_glib_full(ffi::gst_harness_pull_event(self.0.as_ptr()))
627                .ok_or_else(|| glib::bool_error!("Failed to pull event"))
628        }
629    }
630
631    /// Pulls an [`gst::Event`][crate::gst::Event] from the `GAsyncQueue` on the [`Harness`][crate::Harness] srcpad.
632    /// Timeouts after 60 seconds similar to gst_harness_pull.
633    ///
634    /// MT safe.
635    ///
636    /// # Returns
637    ///
638    /// a [`gst::Event`][crate::gst::Event] or [`None`] if timed out.
639    #[doc(alias = "gst_harness_pull_upstream_event")]
640    pub fn pull_upstream_event(&mut self) -> Result<gst::Event, glib::BoolError> {
641        unsafe {
642            Option::<_>::from_glib_full(ffi::gst_harness_pull_upstream_event(self.0.as_ptr()))
643                .ok_or_else(|| glib::bool_error!("Failed to pull event"))
644        }
645    }
646
647    /// Pushes a [`gst::Buffer`][crate::gst::Buffer] on the [`Harness`][crate::Harness] srcpad. The standard way of
648    /// interacting with an harnessed element.
649    ///
650    /// MT safe.
651    /// ## `buffer`
652    /// a [`gst::Buffer`][crate::gst::Buffer] to push
653    ///
654    /// # Returns
655    ///
656    /// a [`gst::FlowReturn`][crate::gst::FlowReturn] with the result from the push
657    #[doc(alias = "gst_harness_push")]
658    pub fn push(&mut self, buffer: gst::Buffer) -> Result<gst::FlowSuccess, gst::FlowError> {
659        unsafe {
660            try_from_glib(ffi::gst_harness_push(
661                self.0.as_ptr(),
662                buffer.into_glib_ptr(),
663            ))
664        }
665    }
666
667    /// Basically a gst_harness_push and a gst_harness_pull in one line. Reflects
668    /// the fact that you often want to do exactly this in your test: Push one buffer
669    /// in, and inspect the outcome.
670    ///
671    /// MT safe.
672    /// ## `buffer`
673    /// a [`gst::Buffer`][crate::gst::Buffer] to push
674    ///
675    /// # Returns
676    ///
677    /// a [`gst::Buffer`][crate::gst::Buffer] or [`None`] if timed out.
678    #[doc(alias = "gst_harness_push_and_pull")]
679    pub fn push_and_pull(&mut self, buffer: gst::Buffer) -> Result<gst::Buffer, glib::BoolError> {
680        unsafe {
681            Option::<_>::from_glib_full(ffi::gst_harness_push_and_pull(
682                self.0.as_ptr(),
683                buffer.into_glib_ptr(),
684            ))
685            .ok_or_else(|| glib::bool_error!("Failed to push and pull buffer"))
686        }
687    }
688
689    /// Pushes an [`gst::Event`][crate::gst::Event] on the [`Harness`][crate::Harness] srcpad.
690    ///
691    /// MT safe.
692    /// ## `event`
693    /// a [`gst::Event`][crate::gst::Event] to push
694    ///
695    /// # Returns
696    ///
697    /// a `gboolean` with the result from the push
698    #[doc(alias = "gst_harness_push_event")]
699    pub fn push_event(&mut self, event: gst::Event) -> bool {
700        unsafe {
701            from_glib(ffi::gst_harness_push_event(
702                self.0.as_ptr(),
703                event.into_glib_ptr(),
704            ))
705        }
706    }
707
708    /// Transfer data from the src-[`Harness`][crate::Harness] to the main-[`Harness`][crate::Harness]. It consists
709    /// of 4 steps:
710    /// 1: Make sure the src is started. (see: gst_harness_play)
711    /// 2: Crank the clock (see: gst_harness_crank_single_clock_wait)
712    /// 3: Pull a [`gst::Buffer`][crate::gst::Buffer] from the src-[`Harness`][crate::Harness] (see: gst_harness_pull)
713    /// 4: Push the same [`gst::Buffer`][crate::gst::Buffer] into the main-[`Harness`][crate::Harness] (see: gst_harness_push)
714    ///
715    /// MT safe.
716    ///
717    /// # Returns
718    ///
719    /// a [`gst::FlowReturn`][crate::gst::FlowReturn] with the result of the push
720    #[doc(alias = "gst_harness_push_from_src")]
721    pub fn push_from_src(&mut self) -> Result<gst::FlowSuccess, gst::FlowError> {
722        unsafe { try_from_glib(ffi::gst_harness_push_from_src(self.0.as_ptr())) }
723    }
724
725    /// Transfer one [`gst::Buffer`][crate::gst::Buffer] from the main-[`Harness`][crate::Harness] to the sink-[`Harness`][crate::Harness].
726    /// See gst_harness_push_from_src for details.
727    ///
728    /// MT safe.
729    ///
730    /// # Returns
731    ///
732    /// a [`gst::FlowReturn`][crate::gst::FlowReturn] with the result of the push
733    #[doc(alias = "gst_harness_push_to_sink")]
734    pub fn push_to_sink(&mut self) -> Result<gst::FlowSuccess, gst::FlowError> {
735        unsafe { try_from_glib(ffi::gst_harness_push_to_sink(self.0.as_ptr())) }
736    }
737
738    /// Pushes an [`gst::Event`][crate::gst::Event] on the [`Harness`][crate::Harness] sinkpad.
739    ///
740    /// MT safe.
741    /// ## `event`
742    /// a [`gst::Event`][crate::gst::Event] to push
743    ///
744    /// # Returns
745    ///
746    /// a `gboolean` with the result from the push
747    #[doc(alias = "gst_harness_push_upstream_event")]
748    pub fn push_upstream_event(&mut self, event: gst::Event) -> bool {
749        unsafe {
750            from_glib(ffi::gst_harness_push_upstream_event(
751                self.0.as_ptr(),
752                event.into_glib_ptr(),
753            ))
754        }
755    }
756
757    /// Get the min latency reported by any harnessed [`gst::Element`][crate::gst::Element].
758    ///
759    /// MT safe.
760    ///
761    /// # Returns
762    ///
763    /// a `GstClockTime` with min latency
764    #[doc(alias = "gst_harness_query_latency")]
765    pub fn query_latency(&self) -> Option<gst::ClockTime> {
766        unsafe { from_glib(ffi::gst_harness_query_latency(self.0.as_ptr())) }
767    }
768
769    //pub fn set(&mut self, element_name: &str, first_property_name: &str, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) {
770    //    unsafe { TODO: call ffi::gst_harness_set() }
771    //}
772
773    /// Setting this will make the harness block in the chain-function, and
774    /// then release when [`pull()`][Self::pull()] or [`try_pull()`][Self::try_pull()] is called.
775    /// Can be useful when wanting to control a src-element that is not implementing
776    /// `gst_clock_id_wait()` so it can't be controlled by the [`TestClock`][crate::TestClock], since
777    /// it otherwise would produce buffers as fast as possible.
778    ///
779    /// MT safe.
780    #[doc(alias = "gst_harness_set_blocking_push_mode")]
781    pub fn set_blocking_push_mode(&mut self) {
782        unsafe {
783            ffi::gst_harness_set_blocking_push_mode(self.0.as_ptr());
784        }
785    }
786
787    /// Sets the [`Harness`][crate::Harness] srcpad and sinkpad caps.
788    ///
789    /// MT safe.
790    /// ## `in_`
791    /// a [`gst::Caps`][crate::gst::Caps] to set on the harness srcpad
792    /// ## `out`
793    /// a [`gst::Caps`][crate::gst::Caps] to set on the harness sinkpad
794    #[doc(alias = "gst_harness_set_caps")]
795    pub fn set_caps(&mut self, in_: gst::Caps, out: gst::Caps) {
796        unsafe {
797            ffi::gst_harness_set_caps(self.0.as_ptr(), in_.into_glib_ptr(), out.into_glib_ptr());
798        }
799    }
800
801    /// Sets the [`Harness`][crate::Harness] srcpad and sinkpad caps using strings.
802    ///
803    /// MT safe.
804    /// ## `in_`
805    /// a `gchar` describing a [`gst::Caps`][crate::gst::Caps] to set on the harness srcpad
806    /// ## `out`
807    /// a `gchar` describing a [`gst::Caps`][crate::gst::Caps] to set on the harness sinkpad
808    #[doc(alias = "gst_harness_set_caps_str")]
809    pub fn set_caps_str(&mut self, in_: &str, out: &str) {
810        unsafe {
811            ffi::gst_harness_set_caps_str(
812                self.0.as_ptr(),
813                in_.to_glib_none().0,
814                out.to_glib_none().0,
815            );
816        }
817    }
818
819    /// When set to [`true`], instead of placing the buffers arriving from the harnessed
820    /// [`gst::Element`][crate::gst::Element] inside the sinkpads `GAsyncQueue`, they are instead unreffed.
821    ///
822    /// MT safe.
823    /// ## `drop_buffers`
824    /// a `gboolean` specifying to drop outgoing buffers or not
825    #[doc(alias = "gst_harness_set_drop_buffers")]
826    pub fn set_drop_buffers(&mut self, drop_buffers: bool) {
827        unsafe {
828            ffi::gst_harness_set_drop_buffers(self.0.as_ptr(), drop_buffers.into_glib());
829        }
830    }
831
832    /// As a convenience, a src-harness will forward [`gst::EventType::StreamStart`][crate::gst::EventType::StreamStart],
833    /// [`gst::EventType::Caps`][crate::gst::EventType::Caps] and [`gst::EventType::Segment`][crate::gst::EventType::Segment] to the main-harness if forwarding
834    /// is enabled, and forward any sticky-events from the main-harness to
835    /// the sink-harness. It will also forward the `GST_QUERY_ALLOCATION`.
836    ///
837    /// If forwarding is disabled, the user will have to either manually push
838    /// these events from the src-harness using [`src_push_event()`][Self::src_push_event()], or
839    /// create and push them manually. While this will allow full control and
840    /// inspection of these events, for the most cases having forwarding enabled
841    /// will be sufficient when writing a test where the src-harness' main function
842    /// is providing data for the main-harness.
843    ///
844    /// Forwarding is enabled by default.
845    ///
846    /// MT safe.
847    /// ## `forwarding`
848    /// a `gboolean` to enable/disable forwarding
849    #[doc(alias = "gst_harness_set_forwarding")]
850    pub fn set_forwarding(&mut self, forwarding: bool) {
851        unsafe {
852            ffi::gst_harness_set_forwarding(self.0.as_ptr(), forwarding.into_glib());
853        }
854    }
855
856    /// Sets the liveness reported by [`Harness`][crate::Harness] when receiving a latency-query.
857    /// The default is [`true`].
858    /// ## `is_live`
859    /// [`true`] for live, [`false`] for non-live
860    #[doc(alias = "gst_harness_set_live")]
861    #[cfg(feature = "v1_20")]
862    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
863    pub fn set_live(&mut self, is_live: bool) {
864        unsafe { ffi::gst_harness_set_live(self.0.as_ptr(), is_live.into_glib()) }
865    }
866
867    //pub fn set_propose_allocator<P: IsA<gst::Allocator>>(&mut self, allocator: Option<&P>, params: Option<&gst::AllocationParams>) {
868    //    unsafe { TODO: call ffi::gst_harness_set_propose_allocator() }
869    //}
870
871    /// Sets the [`Harness`][crate::Harness] sinkpad caps.
872    ///
873    /// MT safe.
874    /// ## `caps`
875    /// a [`gst::Caps`][crate::gst::Caps] to set on the harness sinkpad
876    #[doc(alias = "gst_harness_set_sink_caps")]
877    pub fn set_sink_caps(&mut self, caps: gst::Caps) {
878        unsafe {
879            ffi::gst_harness_set_sink_caps(self.0.as_ptr(), caps.into_glib_ptr());
880        }
881    }
882
883    /// Sets the [`Harness`][crate::Harness] sinkpad caps using a string.
884    ///
885    /// MT safe.
886    /// ## `str`
887    /// a `gchar` describing a [`gst::Caps`][crate::gst::Caps] to set on the harness sinkpad
888    #[doc(alias = "gst_harness_set_sink_caps_str")]
889    pub fn set_sink_caps_str(&mut self, str: &str) {
890        unsafe {
891            ffi::gst_harness_set_sink_caps_str(self.0.as_ptr(), str.to_glib_none().0);
892        }
893    }
894
895    /// Sets the [`Harness`][crate::Harness] srcpad caps. This must be done before any buffers
896    /// can legally be pushed from the harness to the element.
897    ///
898    /// MT safe.
899    /// ## `caps`
900    /// a [`gst::Caps`][crate::gst::Caps] to set on the harness srcpad
901    #[doc(alias = "gst_harness_set_src_caps")]
902    pub fn set_src_caps(&mut self, caps: gst::Caps) {
903        unsafe {
904            ffi::gst_harness_set_src_caps(self.0.as_ptr(), caps.into_glib_ptr());
905        }
906    }
907
908    /// Sets the [`Harness`][crate::Harness] srcpad caps using a string. This must be done before
909    /// any buffers can legally be pushed from the harness to the element.
910    ///
911    /// MT safe.
912    /// ## `str`
913    /// a `gchar` describing a [`gst::Caps`][crate::gst::Caps] to set on the harness srcpad
914    #[doc(alias = "gst_harness_set_src_caps_str")]
915    pub fn set_src_caps_str(&mut self, str: &str) {
916        unsafe {
917            ffi::gst_harness_set_src_caps_str(self.0.as_ptr(), str.to_glib_none().0);
918        }
919    }
920
921    /// Advance the [`TestClock`][crate::TestClock] to a specific time.
922    ///
923    /// MT safe.
924    /// ## `time`
925    /// a `GstClockTime` to advance the clock to
926    ///
927    /// # Returns
928    ///
929    /// a `gboolean` [`true`] if the time could be set. [`false`] if not.
930    #[doc(alias = "gst_harness_set_time")]
931    pub fn set_time(&mut self, time: gst::ClockTime) -> Result<(), glib::BoolError> {
932        unsafe {
933            glib::result_from_gboolean!(
934                ffi::gst_harness_set_time(self.0.as_ptr(), time.into_glib()),
935                "Failed to set time",
936            )
937        }
938    }
939
940    /// Sets the min latency reported by [`Harness`][crate::Harness] when receiving a latency-query
941    /// ## `latency`
942    /// a `GstClockTime` specifying the latency
943    #[doc(alias = "gst_harness_set_upstream_latency")]
944    pub fn set_upstream_latency(&mut self, latency: gst::ClockTime) {
945        unsafe {
946            ffi::gst_harness_set_upstream_latency(self.0.as_ptr(), latency.into_glib());
947        }
948    }
949
950    /// Convenience that calls gst_harness_push_to_sink `pushes` number of times.
951    /// Will abort the pushing if any one push fails.
952    ///
953    /// MT safe.
954    /// ## `pushes`
955    /// a `gint` with the number of calls to gst_harness_push_to_sink
956    ///
957    /// # Returns
958    ///
959    /// a [`gst::FlowReturn`][crate::gst::FlowReturn] with the result of the push
960    #[doc(alias = "gst_harness_sink_push_many")]
961    pub fn sink_push_many(&mut self, pushes: u32) -> Result<gst::FlowSuccess, gst::FlowError> {
962        unsafe {
963            try_from_glib(ffi::gst_harness_sink_push_many(
964                self.0.as_ptr(),
965                pushes as i32,
966            ))
967        }
968    }
969
970    /// Transfer data from the src-[`Harness`][crate::Harness] to the main-[`Harness`][crate::Harness]. Similar to
971    /// gst_harness_push_from_src, this variant allows you to specify how many cranks
972    /// and how many pushes to perform. This can be useful for both moving a lot
973    /// of data at the same time, as well as cases when one crank does not equal one
974    /// buffer to push and v.v.
975    ///
976    /// MT safe.
977    /// ## `cranks`
978    /// a `gint` with the number of calls to gst_harness_crank_single_clock_wait
979    /// ## `pushes`
980    /// a `gint` with the number of calls to gst_harness_push
981    ///
982    /// # Returns
983    ///
984    /// a [`gst::FlowReturn`][crate::gst::FlowReturn] with the result of the push
985    #[doc(alias = "gst_harness_src_crank_and_push_many")]
986    pub fn src_crank_and_push_many(
987        &mut self,
988        cranks: u32,
989        pushes: u32,
990    ) -> Result<gst::FlowSuccess, gst::FlowError> {
991        unsafe {
992            try_from_glib(ffi::gst_harness_src_crank_and_push_many(
993                self.0.as_ptr(),
994                cranks as i32,
995                pushes as i32,
996            ))
997        }
998    }
999
1000    /// Similar to what gst_harness_src_push does with `GstBuffers`, this transfers
1001    /// a [`gst::Event`][crate::gst::Event] from the src-[`Harness`][crate::Harness] to the main-[`Harness`][crate::Harness]. Note that
1002    /// some `GstEvents` are being transferred automagically. Look at sink_forward_pad
1003    /// for details.
1004    ///
1005    /// MT safe.
1006    ///
1007    /// # Returns
1008    ///
1009    /// a `gboolean` with the result of the push
1010    #[doc(alias = "gst_harness_src_push_event")]
1011    pub fn src_push_event(&mut self) -> bool {
1012        unsafe { from_glib(ffi::gst_harness_src_push_event(self.0.as_ptr())) }
1013    }
1014
1015    //pub fn stress_custom_start<'a, P: Into<Option<&'a /*Ignored*/glib::Func>>, Q: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&mut self, init: P, callback: /*Unknown conversion*//*Unimplemented*/Func, data: Q, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1016    //    unsafe { TODO: call ffi::gst_harness_stress_custom_start() }
1017    //}
1018
1019    //pub fn stress_property_start_full(&mut self, name: &str, value: /*Ignored*/&glib::Value, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1020    //    unsafe { TODO: call ffi::gst_harness_stress_property_start_full() }
1021    //}
1022
1023    //pub fn stress_push_buffer_start_full(&mut self, caps: &mut gst::Caps, segment: /*Ignored*/&gst::Segment, buf: &mut gst::Buffer, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1024    //    unsafe { TODO: call ffi::gst_harness_stress_push_buffer_start_full() }
1025    //}
1026
1027    //pub fn stress_push_buffer_with_cb_start_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&mut self, caps: &mut gst::Caps, segment: /*Ignored*/&gst::Segment, func: /*Unknown conversion*//*Unimplemented*/HarnessPrepareBufferFunc, data: P, notify: /*Unknown conversion*//*Unimplemented*/DestroyNotify, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1028    //    unsafe { TODO: call ffi::gst_harness_stress_push_buffer_with_cb_start_full() }
1029    //}
1030
1031    //pub fn stress_push_event_start_full(&mut self, event: &mut gst::Event, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1032    //    unsafe { TODO: call ffi::gst_harness_stress_push_event_start_full() }
1033    //}
1034
1035    //pub fn stress_push_event_with_cb_start_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&mut self, func: /*Unknown conversion*//*Unimplemented*/HarnessPrepareEventFunc, data: P, notify: /*Unknown conversion*//*Unimplemented*/DestroyNotify, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1036    //    unsafe { TODO: call ffi::gst_harness_stress_push_event_with_cb_start_full() }
1037    //}
1038
1039    //pub fn stress_push_upstream_event_start_full(&mut self, event: &mut gst::Event, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1040    //    unsafe { TODO: call ffi::gst_harness_stress_push_upstream_event_start_full() }
1041    //}
1042
1043    //pub fn stress_push_upstream_event_with_cb_start_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&mut self, func: /*Unknown conversion*//*Unimplemented*/HarnessPrepareEventFunc, data: P, notify: /*Unknown conversion*//*Unimplemented*/DestroyNotify, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1044    //    unsafe { TODO: call ffi::gst_harness_stress_push_upstream_event_with_cb_start_full() }
1045    //}
1046
1047    //pub fn stress_requestpad_start_full(&mut self, templ: /*Ignored*/&gst::PadTemplate, name: &str, caps: &mut gst::Caps, release: bool, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1048    //    unsafe { TODO: call ffi::gst_harness_stress_requestpad_start_full() }
1049    //}
1050
1051    //pub fn stress_statechange_start_full(&mut self, sleep: libc::c_ulong) -> /*Ignored*/Option<HarnessThread> {
1052    //    unsafe { TODO: call ffi::gst_harness_stress_statechange_start_full() }
1053    //}
1054
1055    /// Pulls all pending data from the harness and returns it as a single buffer.
1056    ///
1057    /// # Returns
1058    ///
1059    /// the data as a buffer. Unref with `gst_buffer_unref()`
1060    ///  when no longer needed.
1061    #[doc(alias = "gst_harness_take_all_data_as_buffer")]
1062    pub fn take_all_data_as_buffer(&mut self) -> Result<gst::Buffer, glib::BoolError> {
1063        unsafe {
1064            Option::<_>::from_glib_full(ffi::gst_harness_take_all_data_as_buffer(self.0.as_ptr()))
1065                .ok_or_else(|| glib::bool_error!("Failed to take all data as buffer"))
1066        }
1067    }
1068
1069    /// Pulls all pending data from the harness and returns it as a single [`glib::Bytes`][crate::glib::Bytes].
1070    ///
1071    /// # Returns
1072    ///
1073    /// a pointer to the data, newly allocated. Free
1074    ///  with `g_free()` when no longer needed.
1075    #[doc(alias = "gst_harness_take_all_data_as_bytes")]
1076    pub fn take_all_data_as_bytes(&mut self) -> Result<glib::Bytes, glib::BoolError> {
1077        unsafe {
1078            Option::<_>::from_glib_full(ffi::gst_harness_take_all_data_as_bytes(self.0.as_ptr()))
1079                .ok_or_else(|| glib::bool_error!("Failed to take all data as bytes"))
1080        }
1081    }
1082
1083    /// Pulls a [`gst::Buffer`][crate::gst::Buffer] from the `GAsyncQueue` on the [`Harness`][crate::Harness] sinkpad. Unlike
1084    /// gst_harness_pull this will not wait for any buffers if not any are present,
1085    /// and return [`None`] straight away.
1086    ///
1087    /// MT safe.
1088    ///
1089    /// # Returns
1090    ///
1091    /// a [`gst::Buffer`][crate::gst::Buffer] or [`None`] if no buffers are present in the `GAsyncQueue`
1092    #[doc(alias = "gst_harness_try_pull")]
1093    pub fn try_pull(&mut self) -> Option<gst::Buffer> {
1094        unsafe { from_glib_full(ffi::gst_harness_try_pull(self.0.as_ptr())) }
1095    }
1096
1097    /// Pulls an [`gst::Event`][crate::gst::Event] from the `GAsyncQueue` on the [`Harness`][crate::Harness] sinkpad.
1098    /// See gst_harness_try_pull for details.
1099    ///
1100    /// MT safe.
1101    ///
1102    /// # Returns
1103    ///
1104    /// a [`gst::Event`][crate::gst::Event] or [`None`] if no buffers are present in the `GAsyncQueue`
1105    #[doc(alias = "gst_harness_try_pull_event")]
1106    pub fn try_pull_event(&mut self) -> Option<gst::Event> {
1107        unsafe { from_glib_full(ffi::gst_harness_try_pull_event(self.0.as_ptr())) }
1108    }
1109
1110    /// Pulls an [`gst::Event`][crate::gst::Event] from the `GAsyncQueue` on the [`Harness`][crate::Harness] srcpad.
1111    /// See gst_harness_try_pull for details.
1112    ///
1113    /// MT safe.
1114    ///
1115    /// # Returns
1116    ///
1117    /// a [`gst::Event`][crate::gst::Event] or [`None`] if no buffers are present in the `GAsyncQueue`
1118    #[doc(alias = "gst_harness_try_pull_upstream_event")]
1119    pub fn try_pull_upstream_event(&mut self) -> Option<gst::Event> {
1120        unsafe { from_glib_full(ffi::gst_harness_try_pull_upstream_event(self.0.as_ptr())) }
1121    }
1122
1123    /// The number of `GstEvents` currently in the [`Harness`][crate::Harness] srcpad `GAsyncQueue`
1124    ///
1125    /// MT safe.
1126    ///
1127    /// # Returns
1128    ///
1129    /// a `guint` number of events in the queue
1130    #[doc(alias = "gst_harness_upstream_events_in_queue")]
1131    pub fn upstream_events_in_queue(&self) -> u32 {
1132        unsafe { ffi::gst_harness_upstream_events_in_queue(self.0.as_ptr()) }
1133    }
1134
1135    /// The total number of `GstEvents` that has arrived on the [`Harness`][crate::Harness] srcpad
1136    /// This number includes events handled by the harness as well as events
1137    /// that have already been pulled out.
1138    ///
1139    /// MT safe.
1140    ///
1141    /// # Returns
1142    ///
1143    /// a `guint` number of events received
1144    #[doc(alias = "gst_harness_upstream_events_received")]
1145    pub fn upstream_events_received(&self) -> u32 {
1146        unsafe { ffi::gst_harness_upstream_events_received(self.0.as_ptr()) }
1147    }
1148
1149    /// Sets the system [`gst::Clock`][crate::gst::Clock] on the [`Harness`][crate::Harness] [`gst::Element`][crate::gst::Element]
1150    ///
1151    /// MT safe.
1152    #[doc(alias = "gst_harness_use_systemclock")]
1153    pub fn use_systemclock(&mut self) {
1154        unsafe {
1155            ffi::gst_harness_use_systemclock(self.0.as_ptr());
1156        }
1157    }
1158
1159    /// Sets the [`TestClock`][crate::TestClock] on the [`Harness`][crate::Harness] [`gst::Element`][crate::gst::Element]
1160    ///
1161    /// MT safe.
1162    #[doc(alias = "gst_harness_use_testclock")]
1163    pub fn use_testclock(&mut self) {
1164        unsafe {
1165            ffi::gst_harness_use_testclock(self.0.as_ptr());
1166        }
1167    }
1168
1169    /// Waits for `timeout` seconds until `waits` number of `GstClockID` waits is
1170    /// registered with the [`TestClock`][crate::TestClock]. Useful for writing deterministic tests,
1171    /// where you want to make sure that an expected number of waits have been
1172    /// reached.
1173    ///
1174    /// MT safe.
1175    /// ## `waits`
1176    /// a `guint` describing the numbers of `GstClockID` registered with
1177    /// the [`TestClock`][crate::TestClock]
1178    /// ## `timeout`
1179    /// a `guint` describing how many seconds to wait for `waits` to be true
1180    ///
1181    /// # Returns
1182    ///
1183    /// a `gboolean` [`true`] if the waits have been registered, [`false`] if not.
1184    /// (Could be that it timed out waiting or that more waits than waits was found)
1185    #[doc(alias = "gst_harness_wait_for_clock_id_waits")]
1186    pub fn wait_for_clock_id_waits(
1187        &mut self,
1188        waits: u32,
1189        timeout: u32,
1190    ) -> Result<(), glib::BoolError> {
1191        unsafe {
1192            glib::result_from_gboolean!(
1193                ffi::gst_harness_wait_for_clock_id_waits(self.0.as_ptr(), waits, timeout),
1194                "Failed to wait for clock id waits",
1195            )
1196        }
1197    }
1198
1199    #[inline]
1200    unsafe fn from_glib_full(ptr: *mut ffi::GstHarness) -> Harness {
1201        unsafe {
1202            debug_assert!(!ptr.is_null());
1203
1204            Harness(ptr::NonNull::new_unchecked(ptr))
1205        }
1206    }
1207
1208    /// Creates a new harness. Works like [`with_padnames()`][Self::with_padnames()], except it
1209    /// assumes the [`gst::Element`][crate::gst::Element] sinkpad is named "sink" and srcpad is named "src"
1210    ///
1211    /// MT safe.
1212    /// ## `element_name`
1213    /// a `gchar` describing the [`gst::Element`][crate::gst::Element] name
1214    ///
1215    /// # Returns
1216    ///
1217    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1218    /// not be created
1219    #[doc(alias = "gst_harness_new")]
1220    pub fn new(element_name: &str) -> Harness {
1221        assert_initialized_main_thread!();
1222        unsafe { Self::from_glib_full(ffi::gst_harness_new(element_name.to_glib_none().0)) }
1223    }
1224
1225    /// Creates a new empty harness. Use [`add_element_full()`][Self::add_element_full()] to add
1226    /// an [`gst::Element`][crate::gst::Element] to it.
1227    ///
1228    /// MT safe.
1229    ///
1230    /// # Returns
1231    ///
1232    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1233    /// not be created
1234    #[doc(alias = "gst_harness_new_empty")]
1235    pub fn new_empty() -> Harness {
1236        assert_initialized_main_thread!();
1237        unsafe { Self::from_glib_full(ffi::gst_harness_new_empty()) }
1238    }
1239
1240    /// Creates a new harness.
1241    ///
1242    /// MT safe.
1243    /// ## `element`
1244    /// a [`gst::Element`][crate::gst::Element] to attach the harness to (transfer none)
1245    /// ## `hsrc`
1246    /// a [`gst::StaticPadTemplate`][crate::gst::StaticPadTemplate] describing the harness srcpad.
1247    /// [`None`] will not create a harness srcpad.
1248    /// ## `element_sinkpad_name`
1249    /// a `gchar` with the name of the element
1250    /// sinkpad that is then linked to the harness srcpad. Can be a static or request
1251    /// or a sometimes pad that has been added. [`None`] will not get/request a sinkpad
1252    /// from the element. (Like if the element is a src.)
1253    /// ## `hsink`
1254    /// a [`gst::StaticPadTemplate`][crate::gst::StaticPadTemplate] describing the harness sinkpad.
1255    /// [`None`] will not create a harness sinkpad.
1256    /// ## `element_srcpad_name`
1257    /// a `gchar` with the name of the element
1258    /// srcpad that is then linked to the harness sinkpad, similar to the
1259    /// `element_sinkpad_name`.
1260    ///
1261    /// # Returns
1262    ///
1263    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1264    /// not be created
1265    #[doc(alias = "gst_harness_new_full")]
1266    pub fn new_full<P: IsA<gst::Element>>(
1267        element: &P,
1268        hsrc: Option<&gst::StaticPadTemplate>,
1269        element_sinkpad_name: Option<&str>,
1270        hsink: Option<&gst::StaticPadTemplate>,
1271        element_srcpad_name: Option<&str>,
1272    ) -> Harness {
1273        assert_initialized_main_thread!();
1274        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
1275        let element_srcpad_name = element_srcpad_name.to_glib_none();
1276        unsafe {
1277            Self::from_glib_full(ffi::gst_harness_new_full(
1278                element.as_ref().to_glib_none().0,
1279                hsrc.to_glib_none().0 as *mut _,
1280                element_sinkpad_name.0,
1281                hsink.to_glib_none().0 as *mut _,
1282                element_srcpad_name.0,
1283            ))
1284        }
1285    }
1286
1287    /// Creates a new harness, parsing the `launchline` and putting that in a [`gst::Bin`][crate::gst::Bin],
1288    /// and then attches the harness to the bin.
1289    ///
1290    /// MT safe.
1291    /// ## `launchline`
1292    /// a `gchar` describing a gst-launch type line
1293    ///
1294    /// # Returns
1295    ///
1296    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1297    /// not be created
1298    #[doc(alias = "gst_harness_new_parse")]
1299    pub fn new_parse(launchline: &str) -> Harness {
1300        assert_initialized_main_thread!();
1301        unsafe { Self::from_glib_full(ffi::gst_harness_new_parse(launchline.to_glib_none().0)) }
1302    }
1303
1304    /// Creates a new harness. Works in the same way as [`new_full()`][Self::new_full()], only
1305    /// that generic padtemplates are used for the harness src and sinkpads, which
1306    /// will be sufficient in most usecases.
1307    ///
1308    /// MT safe.
1309    /// ## `element`
1310    /// a [`gst::Element`][crate::gst::Element] to attach the harness to (transfer none)
1311    /// ## `element_sinkpad_name`
1312    /// a `gchar` with the name of the element
1313    /// sinkpad that is then linked to the harness srcpad. [`None`] does not attach a
1314    /// sinkpad
1315    /// ## `element_srcpad_name`
1316    /// a `gchar` with the name of the element
1317    /// srcpad that is then linked to the harness sinkpad. [`None`] does not attach a
1318    /// srcpad
1319    ///
1320    /// # Returns
1321    ///
1322    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1323    /// not be created
1324    #[doc(alias = "gst_harness_new_with_element")]
1325    pub fn with_element<P: IsA<gst::Element>>(
1326        element: &P,
1327        element_sinkpad_name: Option<&str>,
1328        element_srcpad_name: Option<&str>,
1329    ) -> Harness {
1330        skip_assert_initialized!();
1331        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
1332        let element_srcpad_name = element_srcpad_name.to_glib_none();
1333        unsafe {
1334            Self::from_glib_full(ffi::gst_harness_new_with_element(
1335                element.as_ref().to_glib_none().0,
1336                element_sinkpad_name.0,
1337                element_srcpad_name.0,
1338            ))
1339        }
1340    }
1341
1342    /// Creates a new harness. Works like [`with_element()`][Self::with_element()],
1343    /// except you specify the factoryname of the [`gst::Element`][crate::gst::Element]
1344    ///
1345    /// MT safe.
1346    /// ## `element_name`
1347    /// a `gchar` describing the [`gst::Element`][crate::gst::Element] name
1348    /// ## `element_sinkpad_name`
1349    /// a `gchar` with the name of the element
1350    /// sinkpad that is then linked to the harness srcpad. [`None`] does not attach a
1351    /// sinkpad
1352    /// ## `element_srcpad_name`
1353    /// a `gchar` with the name of the element
1354    /// srcpad that is then linked to the harness sinkpad. [`None`] does not attach a
1355    /// srcpad
1356    ///
1357    /// # Returns
1358    ///
1359    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1360    /// not be created
1361    #[doc(alias = "gst_harness_new_with_padnames")]
1362    pub fn with_padnames(
1363        element_name: &str,
1364        element_sinkpad_name: Option<&str>,
1365        element_srcpad_name: Option<&str>,
1366    ) -> Harness {
1367        assert_initialized_main_thread!();
1368        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
1369        let element_srcpad_name = element_srcpad_name.to_glib_none();
1370        unsafe {
1371            Self::from_glib_full(ffi::gst_harness_new_with_padnames(
1372                element_name.to_glib_none().0,
1373                element_sinkpad_name.0,
1374                element_srcpad_name.0,
1375            ))
1376        }
1377    }
1378
1379    #[doc(alias = "gst_harness_new_with_templates")]
1380    pub fn with_templates(
1381        element_name: &str,
1382        hsrc: Option<&gst::StaticPadTemplate>,
1383        hsink: Option<&gst::StaticPadTemplate>,
1384    ) -> Harness {
1385        assert_initialized_main_thread!();
1386        unsafe {
1387            Self::from_glib_full(ffi::gst_harness_new_with_templates(
1388                element_name.to_glib_none().0,
1389                hsrc.to_glib_none().0 as *mut _,
1390                hsink.to_glib_none().0 as *mut _,
1391            ))
1392        }
1393    }
1394
1395    //pub fn stress_thread_stop(t: /*Ignored*/&mut HarnessThread) -> u32 {
1396    //    unsafe { TODO: call ffi::gst_harness_stress_thread_stop() }
1397    //}
1398
1399    #[doc(alias = "get_element")]
1400    pub fn element(&self) -> Option<gst::Element> {
1401        unsafe {
1402            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
1403            let ptr = (*self.0.as_ptr()).element;
1404
1405            if ptr.is_null() {
1406                return None;
1407            }
1408
1409            // Clear floating flag if it is set
1410            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
1411                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
1412            }
1413
1414            from_glib_none(ptr)
1415        }
1416    }
1417
1418    #[doc(alias = "get_sinkpad")]
1419    pub fn sinkpad(&self) -> Option<gst::Pad> {
1420        unsafe {
1421            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
1422            let ptr = (*self.0.as_ptr()).sinkpad;
1423
1424            if ptr.is_null() {
1425                return None;
1426            }
1427
1428            // Clear floating flag if it is set
1429            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
1430                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
1431            }
1432
1433            from_glib_none(ptr)
1434        }
1435    }
1436
1437    #[doc(alias = "get_srcpad")]
1438    pub fn srcpad(&self) -> Option<gst::Pad> {
1439        unsafe {
1440            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
1441            let ptr = (*self.0.as_ptr()).srcpad;
1442
1443            if ptr.is_null() {
1444                return None;
1445            }
1446
1447            // Clear floating flag if it is set
1448            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
1449                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
1450            }
1451
1452            from_glib_none(ptr)
1453        }
1454    }
1455
1456    #[doc(alias = "get_sink_harness")]
1457    pub fn sink_harness(&self) -> Option<Ref<'_>> {
1458        unsafe {
1459            if (*self.0.as_ptr()).sink_harness.is_null() {
1460                None
1461            } else {
1462                Some(Ref(
1463                    &*((&(*self.0.as_ptr()).sink_harness) as *const *mut ffi::GstHarness
1464                        as *const Harness),
1465                ))
1466            }
1467        }
1468    }
1469
1470    #[doc(alias = "get_src_harness")]
1471    pub fn src_harness(&self) -> Option<Ref<'_>> {
1472        unsafe {
1473            if (*self.0.as_ptr()).src_harness.is_null() {
1474                None
1475            } else {
1476                Some(Ref(
1477                    &*((&(*self.0.as_ptr()).src_harness) as *const *mut ffi::GstHarness
1478                        as *const Harness),
1479                ))
1480            }
1481        }
1482    }
1483
1484    #[doc(alias = "get_mut_sink_harness")]
1485    pub fn sink_harness_mut(&mut self) -> Option<RefMut<'_>> {
1486        unsafe {
1487            if (*self.0.as_ptr()).sink_harness.is_null() {
1488                None
1489            } else {
1490                Some(RefMut(
1491                    &mut *((&mut (*self.0.as_ptr()).sink_harness) as *mut *mut ffi::GstHarness
1492                        as *mut Harness),
1493                ))
1494            }
1495        }
1496    }
1497
1498    #[doc(alias = "get_mut_src_harness")]
1499    pub fn src_harness_mut(&mut self) -> Option<RefMut<'_>> {
1500        unsafe {
1501            if (*self.0.as_ptr()).src_harness.is_null() {
1502                None
1503            } else {
1504                Some(RefMut(
1505                    &mut *((&mut (*self.0.as_ptr()).src_harness) as *mut *mut ffi::GstHarness
1506                        as *mut Harness),
1507                ))
1508            }
1509        }
1510    }
1511}
1512
1513#[derive(Debug)]
1514pub struct Ref<'a>(&'a Harness);
1515
1516impl ops::Deref for Ref<'_> {
1517    type Target = Harness;
1518
1519    #[inline]
1520    fn deref(&self) -> &Harness {
1521        self.0
1522    }
1523}
1524
1525#[derive(Debug)]
1526pub struct RefMut<'a>(&'a mut Harness);
1527
1528impl ops::Deref for RefMut<'_> {
1529    type Target = Harness;
1530
1531    #[inline]
1532    fn deref(&self) -> &Harness {
1533        self.0
1534    }
1535}
1536
1537impl ops::DerefMut for RefMut<'_> {
1538    #[inline]
1539    fn deref_mut(&mut self) -> &mut Harness {
1540        self.0
1541    }
1542}
1543
1544#[cfg(test)]
1545mod tests {
1546    use super::*;
1547
1548    #[test]
1549    fn test_identity_push_pull() {
1550        gst::init().unwrap();
1551
1552        let mut h = Harness::new("identity");
1553        h.set_src_caps_str("application/test");
1554        let buf = gst::Buffer::new();
1555        let buf = h.push_and_pull(buf);
1556        assert!(buf.is_ok());
1557    }
1558}