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}