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