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::{ffi, TestClock};
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        debug_assert!(!ptr.is_null());
1202
1203        Harness(ptr::NonNull::new_unchecked(ptr))
1204    }
1205
1206    /// Creates a new harness. Works like [`with_padnames()`][Self::with_padnames()], except it
1207    /// assumes the [`gst::Element`][crate::gst::Element] sinkpad is named "sink" and srcpad is named "src"
1208    ///
1209    /// MT safe.
1210    /// ## `element_name`
1211    /// a `gchar` describing the [`gst::Element`][crate::gst::Element] name
1212    ///
1213    /// # Returns
1214    ///
1215    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1216    /// not be created
1217    #[doc(alias = "gst_harness_new")]
1218    pub fn new(element_name: &str) -> Harness {
1219        assert_initialized_main_thread!();
1220        unsafe { Self::from_glib_full(ffi::gst_harness_new(element_name.to_glib_none().0)) }
1221    }
1222
1223    /// Creates a new empty harness. Use [`add_element_full()`][Self::add_element_full()] to add
1224    /// an [`gst::Element`][crate::gst::Element] to it.
1225    ///
1226    /// MT safe.
1227    ///
1228    /// # Returns
1229    ///
1230    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1231    /// not be created
1232    #[doc(alias = "gst_harness_new_empty")]
1233    pub fn new_empty() -> Harness {
1234        assert_initialized_main_thread!();
1235        unsafe { Self::from_glib_full(ffi::gst_harness_new_empty()) }
1236    }
1237
1238    /// Creates a new harness.
1239    ///
1240    /// MT safe.
1241    /// ## `element`
1242    /// a [`gst::Element`][crate::gst::Element] to attach the harness to (transfer none)
1243    /// ## `hsrc`
1244    /// a [`gst::StaticPadTemplate`][crate::gst::StaticPadTemplate] describing the harness srcpad.
1245    /// [`None`] will not create a harness srcpad.
1246    /// ## `element_sinkpad_name`
1247    /// a `gchar` with the name of the element
1248    /// sinkpad that is then linked to the harness srcpad. Can be a static or request
1249    /// or a sometimes pad that has been added. [`None`] will not get/request a sinkpad
1250    /// from the element. (Like if the element is a src.)
1251    /// ## `hsink`
1252    /// a [`gst::StaticPadTemplate`][crate::gst::StaticPadTemplate] describing the harness sinkpad.
1253    /// [`None`] will not create a harness sinkpad.
1254    /// ## `element_srcpad_name`
1255    /// a `gchar` with the name of the element
1256    /// srcpad that is then linked to the harness sinkpad, similar to the
1257    /// `element_sinkpad_name`.
1258    ///
1259    /// # Returns
1260    ///
1261    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1262    /// not be created
1263    #[doc(alias = "gst_harness_new_full")]
1264    pub fn new_full<P: IsA<gst::Element>>(
1265        element: &P,
1266        hsrc: Option<&gst::StaticPadTemplate>,
1267        element_sinkpad_name: Option<&str>,
1268        hsink: Option<&gst::StaticPadTemplate>,
1269        element_srcpad_name: Option<&str>,
1270    ) -> Harness {
1271        assert_initialized_main_thread!();
1272        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
1273        let element_srcpad_name = element_srcpad_name.to_glib_none();
1274        unsafe {
1275            Self::from_glib_full(ffi::gst_harness_new_full(
1276                element.as_ref().to_glib_none().0,
1277                hsrc.to_glib_none().0 as *mut _,
1278                element_sinkpad_name.0,
1279                hsink.to_glib_none().0 as *mut _,
1280                element_srcpad_name.0,
1281            ))
1282        }
1283    }
1284
1285    /// Creates a new harness, parsing the `launchline` and putting that in a [`gst::Bin`][crate::gst::Bin],
1286    /// and then attches the harness to the bin.
1287    ///
1288    /// MT safe.
1289    /// ## `launchline`
1290    /// a `gchar` describing a gst-launch type line
1291    ///
1292    /// # Returns
1293    ///
1294    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1295    /// not be created
1296    #[doc(alias = "gst_harness_new_parse")]
1297    pub fn new_parse(launchline: &str) -> Harness {
1298        assert_initialized_main_thread!();
1299        unsafe { Self::from_glib_full(ffi::gst_harness_new_parse(launchline.to_glib_none().0)) }
1300    }
1301
1302    /// Creates a new harness. Works in the same way as [`new_full()`][Self::new_full()], only
1303    /// that generic padtemplates are used for the harness src and sinkpads, which
1304    /// will be sufficient in most usecases.
1305    ///
1306    /// MT safe.
1307    /// ## `element`
1308    /// a [`gst::Element`][crate::gst::Element] to attach the harness to (transfer none)
1309    /// ## `element_sinkpad_name`
1310    /// a `gchar` with the name of the element
1311    /// sinkpad that is then linked to the harness srcpad. [`None`] does not attach a
1312    /// sinkpad
1313    /// ## `element_srcpad_name`
1314    /// a `gchar` with the name of the element
1315    /// srcpad that is then linked to the harness sinkpad. [`None`] does not attach a
1316    /// srcpad
1317    ///
1318    /// # Returns
1319    ///
1320    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1321    /// not be created
1322    #[doc(alias = "gst_harness_new_with_element")]
1323    pub fn with_element<P: IsA<gst::Element>>(
1324        element: &P,
1325        element_sinkpad_name: Option<&str>,
1326        element_srcpad_name: Option<&str>,
1327    ) -> Harness {
1328        skip_assert_initialized!();
1329        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
1330        let element_srcpad_name = element_srcpad_name.to_glib_none();
1331        unsafe {
1332            Self::from_glib_full(ffi::gst_harness_new_with_element(
1333                element.as_ref().to_glib_none().0,
1334                element_sinkpad_name.0,
1335                element_srcpad_name.0,
1336            ))
1337        }
1338    }
1339
1340    /// Creates a new harness. Works like [`with_element()`][Self::with_element()],
1341    /// except you specify the factoryname of the [`gst::Element`][crate::gst::Element]
1342    ///
1343    /// MT safe.
1344    /// ## `element_name`
1345    /// a `gchar` describing the [`gst::Element`][crate::gst::Element] name
1346    /// ## `element_sinkpad_name`
1347    /// a `gchar` with the name of the element
1348    /// sinkpad that is then linked to the harness srcpad. [`None`] does not attach a
1349    /// sinkpad
1350    /// ## `element_srcpad_name`
1351    /// a `gchar` with the name of the element
1352    /// srcpad that is then linked to the harness sinkpad. [`None`] does not attach a
1353    /// srcpad
1354    ///
1355    /// # Returns
1356    ///
1357    /// a [`Harness`][crate::Harness], or [`None`] if the harness could
1358    /// not be created
1359    #[doc(alias = "gst_harness_new_with_padnames")]
1360    pub fn with_padnames(
1361        element_name: &str,
1362        element_sinkpad_name: Option<&str>,
1363        element_srcpad_name: Option<&str>,
1364    ) -> Harness {
1365        assert_initialized_main_thread!();
1366        let element_sinkpad_name = element_sinkpad_name.to_glib_none();
1367        let element_srcpad_name = element_srcpad_name.to_glib_none();
1368        unsafe {
1369            Self::from_glib_full(ffi::gst_harness_new_with_padnames(
1370                element_name.to_glib_none().0,
1371                element_sinkpad_name.0,
1372                element_srcpad_name.0,
1373            ))
1374        }
1375    }
1376
1377    #[doc(alias = "gst_harness_new_with_templates")]
1378    pub fn with_templates(
1379        element_name: &str,
1380        hsrc: Option<&gst::StaticPadTemplate>,
1381        hsink: Option<&gst::StaticPadTemplate>,
1382    ) -> Harness {
1383        assert_initialized_main_thread!();
1384        unsafe {
1385            Self::from_glib_full(ffi::gst_harness_new_with_templates(
1386                element_name.to_glib_none().0,
1387                hsrc.to_glib_none().0 as *mut _,
1388                hsink.to_glib_none().0 as *mut _,
1389            ))
1390        }
1391    }
1392
1393    //pub fn stress_thread_stop(t: /*Ignored*/&mut HarnessThread) -> u32 {
1394    //    unsafe { TODO: call ffi::gst_harness_stress_thread_stop() }
1395    //}
1396
1397    #[doc(alias = "get_element")]
1398    pub fn element(&self) -> Option<gst::Element> {
1399        unsafe {
1400            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
1401            let ptr = (*self.0.as_ptr()).element;
1402
1403            if ptr.is_null() {
1404                return None;
1405            }
1406
1407            // Clear floating flag if it is set
1408            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
1409                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
1410            }
1411
1412            from_glib_none(ptr)
1413        }
1414    }
1415
1416    #[doc(alias = "get_sinkpad")]
1417    pub fn sinkpad(&self) -> Option<gst::Pad> {
1418        unsafe {
1419            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
1420            let ptr = (*self.0.as_ptr()).sinkpad;
1421
1422            if ptr.is_null() {
1423                return None;
1424            }
1425
1426            // Clear floating flag if it is set
1427            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
1428                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
1429            }
1430
1431            from_glib_none(ptr)
1432        }
1433    }
1434
1435    #[doc(alias = "get_srcpad")]
1436    pub fn srcpad(&self) -> Option<gst::Pad> {
1437        unsafe {
1438            // Work around https://gitlab.freedesktop.org/gstreamer/gstreamer/merge_requests/31
1439            let ptr = (*self.0.as_ptr()).srcpad;
1440
1441            if ptr.is_null() {
1442                return None;
1443            }
1444
1445            // Clear floating flag if it is set
1446            if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
1447                glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
1448            }
1449
1450            from_glib_none(ptr)
1451        }
1452    }
1453
1454    #[doc(alias = "get_sink_harness")]
1455    pub fn sink_harness(&self) -> Option<Ref> {
1456        unsafe {
1457            if (*self.0.as_ptr()).sink_harness.is_null() {
1458                None
1459            } else {
1460                Some(Ref(
1461                    &*((&(*self.0.as_ptr()).sink_harness) as *const *mut ffi::GstHarness
1462                        as *const Harness),
1463                ))
1464            }
1465        }
1466    }
1467
1468    #[doc(alias = "get_src_harness")]
1469    pub fn src_harness(&self) -> Option<Ref> {
1470        unsafe {
1471            if (*self.0.as_ptr()).src_harness.is_null() {
1472                None
1473            } else {
1474                Some(Ref(
1475                    &*((&(*self.0.as_ptr()).src_harness) as *const *mut ffi::GstHarness
1476                        as *const Harness),
1477                ))
1478            }
1479        }
1480    }
1481
1482    #[doc(alias = "get_mut_sink_harness")]
1483    pub fn sink_harness_mut(&mut self) -> Option<RefMut> {
1484        unsafe {
1485            if (*self.0.as_ptr()).sink_harness.is_null() {
1486                None
1487            } else {
1488                Some(RefMut(
1489                    &mut *((&mut (*self.0.as_ptr()).sink_harness) as *mut *mut ffi::GstHarness
1490                        as *mut Harness),
1491                ))
1492            }
1493        }
1494    }
1495
1496    #[doc(alias = "get_mut_src_harness")]
1497    pub fn src_harness_mut(&mut self) -> Option<RefMut> {
1498        unsafe {
1499            if (*self.0.as_ptr()).src_harness.is_null() {
1500                None
1501            } else {
1502                Some(RefMut(
1503                    &mut *((&mut (*self.0.as_ptr()).src_harness) as *mut *mut ffi::GstHarness
1504                        as *mut Harness),
1505                ))
1506            }
1507        }
1508    }
1509}
1510
1511#[derive(Debug)]
1512pub struct Ref<'a>(&'a Harness);
1513
1514impl ops::Deref for Ref<'_> {
1515    type Target = Harness;
1516
1517    #[inline]
1518    fn deref(&self) -> &Harness {
1519        self.0
1520    }
1521}
1522
1523#[derive(Debug)]
1524pub struct RefMut<'a>(&'a mut Harness);
1525
1526impl ops::Deref for RefMut<'_> {
1527    type Target = Harness;
1528
1529    #[inline]
1530    fn deref(&self) -> &Harness {
1531        self.0
1532    }
1533}
1534
1535impl ops::DerefMut for RefMut<'_> {
1536    #[inline]
1537    fn deref_mut(&mut self) -> &mut Harness {
1538        self.0
1539    }
1540}
1541
1542#[cfg(test)]
1543mod tests {
1544    use super::*;
1545
1546    #[test]
1547    fn test_identity_push_pull() {
1548        gst::init().unwrap();
1549
1550        let mut h = Harness::new("identity");
1551        h.set_src_caps_str("application/test");
1552        let buf = gst::Buffer::new();
1553        let buf = h.push_and_pull(buf);
1554        assert!(buf.is_ok());
1555    }
1556}