// Take a look at the license at the top of the repository in the LICENSE file. use glib::{prelude::*, subclass::prelude::*, translate::*}; use super::prelude::*; use crate::{Clock, ClockError, ClockId, ClockReturn, ClockSuccess, ClockTime, ClockTimeDiff}; pub trait ClockImpl: ClockImplExt + GstObjectImpl + Send + Sync { fn change_resolution(&self, old_resolution: ClockTime, new_resolution: ClockTime) -> ClockTime { self.parent_change_resolution(old_resolution, new_resolution) } fn resolution(&self) -> ClockTime { self.parent_resolution() } fn internal_time(&self) -> ClockTime { self.parent_internal_time() } fn wait(&self, id: &ClockId) -> (Result, ClockTimeDiff) { self.parent_wait(id) } fn wait_async(&self, id: &ClockId) -> Result { self.parent_wait_async(id) } fn unschedule(&self, id: &ClockId) { self.parent_unschedule(id) } } mod sealed { pub trait Sealed {} impl Sealed for T {} } pub trait ClockImplExt: sealed::Sealed + ObjectSubclass { fn parent_change_resolution( &self, old_resolution: ClockTime, new_resolution: ClockTime, ) -> ClockTime; fn parent_resolution(&self) -> ClockTime { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass; try_from_glib( (*parent_class) .get_resolution .map(|f| f(self.obj().unsafe_cast_ref::().to_glib_none().0)) .unwrap_or(1), ) .expect("undefined resolution") } } fn parent_internal_time(&self) -> ClockTime { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass; try_from_glib( (*parent_class) .get_internal_time .map(|f| f(self.obj().unsafe_cast_ref::().to_glib_none().0)) .unwrap_or(0), ) .expect("undefined internal_time") } } fn parent_wait(&self, id: &ClockId) -> (Result, ClockTimeDiff) { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass; let mut jitter = 0; ( try_from_glib( (*parent_class) .wait .map(|f| { f( self.obj().unsafe_cast_ref::().to_glib_none().0, id.as_ptr() as *mut ffi::GstClockEntry, &mut jitter, ) }) .unwrap_or(ffi::GST_CLOCK_UNSUPPORTED), ), jitter, ) } } fn parent_wait_async(&self, id: &ClockId) -> Result { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass; try_from_glib( (*parent_class) .wait_async .map(|f| { f( self.obj().unsafe_cast_ref::().to_glib_none().0, id.as_ptr() as *mut ffi::GstClockEntry, ) }) .unwrap_or(ffi::GST_CLOCK_UNSUPPORTED), ) } } fn parent_unschedule(&self, id: &ClockId) { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass; if let Some(func) = (*parent_class).unschedule { func( self.obj().unsafe_cast_ref::().to_glib_none().0, id.as_ptr() as *mut ffi::GstClockEntry, ); } } } fn wake_id(&self, id: &ClockId) { let clock = self.obj(); let clock = unsafe { clock.unsafe_cast_ref::() }; cfg_if::cfg_if! { if #[cfg(feature = "v1_16")] { assert!(id.uses_clock(clock)); } else { unsafe { let ptr = id.as_ptr() as *mut ffi::GstClockEntry; assert_eq!((*ptr).clock, clock.to_glib_none().0); } } } unsafe { let ptr = id.as_ptr() as *mut ffi::GstClockEntry; if let Some(func) = (*ptr).func { func( clock.to_glib_none().0, (*ptr).time, ptr as ffi::GstClockID, (*ptr).user_data, ); } if (*ptr).type_ == ffi::GST_CLOCK_ENTRY_PERIODIC { (*ptr).time += (*ptr).interval; } } } } impl ClockImplExt for T { fn parent_change_resolution( &self, old_resolution: ClockTime, new_resolution: ClockTime, ) -> ClockTime { unsafe { let data = Self::type_data(); let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass; if let Some(func) = (*parent_class).change_resolution { try_from_glib(func( self.obj().unsafe_cast_ref::().to_glib_none().0, old_resolution.into_glib(), new_resolution.into_glib(), )) .expect("undefined resolution") } else { self.resolution() } } } } unsafe impl IsSubclassable for Clock { fn class_init(klass: &mut glib::Class) { Self::parent_class_init::(klass); let klass = klass.as_mut(); klass.change_resolution = Some(clock_change_resolution::); klass.get_resolution = Some(clock_get_resolution::); klass.get_internal_time = Some(clock_get_internal_time::); klass.wait = Some(clock_wait::); klass.wait_async = Some(clock_wait_async::); klass.unschedule = Some(clock_unschedule::); } } unsafe extern "C" fn clock_change_resolution( ptr: *mut ffi::GstClock, old_resolution: ffi::GstClockTime, new_resolution: ffi::GstClockTime, ) -> ffi::GstClockTime { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); let old_resolution = match from_glib(old_resolution) { Some(old_resolution) => old_resolution, None => return ffi::GST_CLOCK_TIME_NONE, }; let new_resolution = match from_glib(new_resolution) { Some(new_resolution) => new_resolution, None => return ffi::GST_CLOCK_TIME_NONE, }; imp.change_resolution(old_resolution, new_resolution) .into_glib() } unsafe extern "C" fn clock_get_resolution( ptr: *mut ffi::GstClock, ) -> ffi::GstClockTime { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); imp.resolution().into_glib() } unsafe extern "C" fn clock_get_internal_time( ptr: *mut ffi::GstClock, ) -> ffi::GstClockTime { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); imp.internal_time().into_glib() } unsafe extern "C" fn clock_wait( ptr: *mut ffi::GstClock, id: *mut ffi::GstClockEntry, jitter: *mut ffi::GstClockTimeDiff, ) -> ffi::GstClockReturn { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); let (res, j) = imp.wait(&from_glib_borrow(id as ffi::GstClockID)); if !jitter.is_null() { *jitter = j; } ClockReturn::from(res).into_glib() } unsafe extern "C" fn clock_wait_async( ptr: *mut ffi::GstClock, id: *mut ffi::GstClockEntry, ) -> ffi::GstClockReturn { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); ClockReturn::from(imp.wait_async(&from_glib_borrow(id as ffi::GstClockID))).into_glib() } unsafe extern "C" fn clock_unschedule( ptr: *mut ffi::GstClock, id: *mut ffi::GstClockEntry, ) { let instance = &*(ptr as *mut T::Instance); let imp = instance.imp(); imp.unschedule(&from_glib_borrow(id as ffi::GstClockID)); }