1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Take a look at the license at the top of the repository in the LICENSE file.

use std::num::NonZeroU64;

use crate::PtpClock;

use glib::prelude::*;
use glib::translate::*;

impl PtpClock {
    /// Creates a new PTP clock instance that exports the PTP time of the master
    /// clock in `domain`. This clock can be slaved to other clocks as needed.
    ///
    /// If `gst_ptp_init()` was not called before, this will call `gst_ptp_init()` with
    /// default parameters.
    ///
    /// This clock only returns valid timestamps after it received the first
    /// times from the PTP master clock on the network. Once this happens the
    /// GstPtpClock::internal-clock property will become non-NULL. You can
    /// check this with [`ClockExtManual::wait_for_sync()`][crate::gst::prelude::ClockExtManual::wait_for_sync()], the GstClock::synced signal and
    /// [`ClockExtManual::is_synced()`][crate::gst::prelude::ClockExtManual::is_synced()].
    /// ## `name`
    /// Name of the clock
    /// ## `domain`
    /// PTP domain
    ///
    /// # Returns
    ///
    /// A new [`gst::Clock`][crate::gst::Clock]
    #[doc(alias = "gst_ptp_clock_new")]
    pub fn new(name: Option<&str>, domain: u32) -> PtpClock {
        assert_initialized_main_thread!();
        let name = name.to_glib_none();
        let (major, minor, _, _) = gst::version();
        if (major, minor) > (1, 12) {
            unsafe {
                gst::Clock::from_glib_full(ffi::gst_ptp_clock_new(name.0, domain)).unsafe_cast()
            }
        } else {
            // Workaround for bad floating reference handling in 1.12. This issue was fixed for 1.13
            unsafe {
                gst::Clock::from_glib_none(ffi::gst_ptp_clock_new(name.0, domain)).unsafe_cast()
            }
        }
    }

    // rustdoc-stripper-ignore-next
    /// Initialize GStreamer PTP clock support
    ///
    /// This is automatically called once the first PTP clock instance is created.
    #[doc(alias = "gst_ptp_init")]
    pub fn init(clock_id: Option<u64>, interfaces: &[&str]) -> Result<(), glib::BoolError> {
        skip_assert_initialized!();
        unsafe {
            let res: bool = from_glib(ffi::gst_ptp_init(
                clock_id.unwrap_or(u64::MAX),
                interfaces.to_glib_none().0,
            ));

            if res {
                Ok(())
            } else {
                Err(glib::bool_error!("Failed to initialize PTP subsystem"))
            }
        }
    }

    // rustdoc-stripper-ignore-next
    /// Deinitialize GStreamer PTP clock support
    ///
    /// Any PTP clocks that are still running will not receive any updates anymore.
    #[doc(alias = "gst_ptp_deinit")]
    pub fn deinit() {
        unsafe {
            ffi::gst_ptp_deinit();
        }
    }

    // rustdoc-stripper-ignore-next
    /// Check if the GStreamer PTP clock support is initialized
    #[doc(alias = "gst_ptp_is_initialized")]
    pub fn is_initialized() -> bool {
        unsafe { from_glib(ffi::gst_ptp_is_initialized()) }
    }

    // rustdoc-stripper-ignore-next
    /// Check if GStreamer PTP clocks are supported
    #[doc(alias = "gst_ptp_is_supported")]
    pub fn is_supported() -> bool {
        unsafe { from_glib(ffi::gst_ptp_is_supported()) }
    }

    // rustdoc-stripper-ignore-next
    /// Add a PTP clock statistics callback
    #[doc(alias = "gst_ptp_statistics_callback_add")]
    pub fn add_statistics_callback<
        F: Fn(u8, &gst::StructureRef) -> glib::Continue + 'static + Send + Sync,
    >(
        func: F,
    ) -> PtpStatisticsCallback {
        unsafe {
            unsafe extern "C" fn trampoline<
                F: Fn(u8, &gst::StructureRef) -> glib::Continue + 'static + Send + Sync,
            >(
                domain: u8,
                stats: *const gst::ffi::GstStructure,
                user_data: glib::ffi::gpointer,
            ) -> glib::ffi::gboolean {
                let callback = &*(user_data as *const F);
                callback(domain, gst::StructureRef::from_glib_borrow(stats)).into_glib()
            }

            unsafe extern "C" fn destroy<
                F: Fn(u8, &gst::StructureRef) -> glib::Continue + 'static + Send + Sync,
            >(
                user_data: glib::ffi::gpointer,
            ) {
                let _ = Box::from_raw(user_data as *mut F);
            }

            let user_data = Box::new(func);
            let id = ffi::gst_ptp_statistics_callback_add(
                Some(trampoline::<F>),
                Box::into_raw(user_data) as glib::ffi::gpointer,
                Some(destroy::<F>),
            );
            assert_ne!(id, 0);

            PtpStatisticsCallback(NonZeroU64::new_unchecked(id))
        }
    }
}

#[derive(Debug)]
pub struct PtpStatisticsCallback(NonZeroU64);

impl PtpStatisticsCallback {
    #[doc(alias = "gst_ptp_statistics_callback_remove")]
    pub fn remove(self) {
        unsafe {
            ffi::gst_ptp_statistics_callback_remove(self.0.get() as _);
        }
    }
}