Skip to main content

gstreamer_rtsp_server/subclass/
rtsp_media.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6
7use crate::{RTSPMedia, RTSPThread, ffi};
8
9#[derive(Debug)]
10pub struct SDPInfo(ptr::NonNull<ffi::GstSDPInfo>);
11
12impl SDPInfo {
13    pub fn is_ipv6(&self) -> bool {
14        unsafe { from_glib(self.0.as_ref().is_ipv6) }
15    }
16
17    pub fn server_ip(&self) -> &str {
18        unsafe {
19            use std::ffi::CStr;
20            CStr::from_ptr(self.0.as_ref().server_ip).to_str().unwrap()
21        }
22    }
23}
24
25pub trait RTSPMediaImpl: ObjectImpl + ObjectSubclass<Type: IsA<RTSPMedia>> + Send + Sync {
26    /// handle a message
27    fn handle_message(&self, message: &gst::MessageRef) -> bool {
28        self.parent_handle_message(message)
29    }
30
31    /// Prepare `self` for streaming. This function will create the objects
32    /// to manage the streaming. A pipeline must have been set on `self` with
33    /// [`RTSPMediaExtManual::take_pipeline()`][crate::prelude::RTSPMediaExtManual::take_pipeline()].
34    ///
35    /// It will preroll the pipeline and collect vital information about the streams
36    /// such as the duration.
37    /// ## `thread`
38    /// a [`RTSPThread`][crate::RTSPThread] to run the
39    ///  bus handler or [`None`]
40    ///
41    /// # Returns
42    ///
43    /// [`true`] on success.
44    fn prepare(&self, thread: &RTSPThread) -> Result<(), gst::LoggableError> {
45        self.parent_prepare(thread)
46    }
47
48    /// Unprepare `self`. After this call, the media should be prepared again before
49    /// it can be used again. If the media is set to be non-reusable, a new instance
50    /// must be created.
51    ///
52    /// # Returns
53    ///
54    /// [`true`] on success.
55    fn unprepare(&self) -> Result<(), gst::LoggableError> {
56        self.parent_unprepare()
57    }
58
59    /// Suspend `self`. The state of the pipeline managed by `self` is set to
60    /// GST_STATE_NULL but all streams are kept. `self` can be prepared again
61    /// with [`RTSPMediaExt::unsuspend()`][crate::prelude::RTSPMediaExt::unsuspend()]
62    ///
63    /// `self` must be prepared with [`RTSPMediaExt::prepare()`][crate::prelude::RTSPMediaExt::prepare()];
64    ///
65    /// # Returns
66    ///
67    /// [`true`] on success.
68    fn suspend(&self) -> Result<(), gst::LoggableError> {
69        self.parent_suspend()
70    }
71
72    /// Unsuspend `self` if it was in a suspended state. This method does nothing
73    /// when the media was not in the suspended state.
74    ///
75    /// # Returns
76    ///
77    /// [`true`] on success.
78    fn unsuspend(&self) -> Result<(), gst::LoggableError> {
79        self.parent_unsuspend()
80    }
81
82    // TODO missing: convert_range
83
84    /// query the current position in the pipeline
85    fn query_position(&self) -> Option<gst::ClockTime> {
86        self.parent_query_position()
87    }
88
89    /// query when playback will stop
90    fn query_stop(&self) -> Option<gst::ClockTime> {
91        self.parent_query_stop()
92    }
93
94    fn create_rtpbin(&self) -> Option<gst::Element> {
95        self.parent_create_rtpbin()
96    }
97
98    fn setup_rtpbin(&self, rtpbin: &gst::Element) -> Result<(), gst::LoggableError> {
99        self.parent_setup_rtpbin(rtpbin)
100    }
101
102    /// Add `self` specific info to `sdp`. `info` is used to configure the connection
103    /// information in the SDP.
104    /// ## `sdp`
105    /// a `GstSDPMessage`
106    /// ## `info`
107    /// a `GstSDPInfo`
108    ///
109    /// # Returns
110    ///
111    /// TRUE on success.
112    fn setup_sdp(
113        &self,
114        sdp: &mut gst_sdp::SDPMessageRef,
115        info: &SDPInfo,
116    ) -> Result<(), gst::LoggableError> {
117        self.parent_setup_sdp(sdp, info)
118    }
119
120    fn new_stream(&self, stream: &crate::RTSPStream) {
121        self.parent_new_stream(stream);
122    }
123
124    fn removed_stream(&self, stream: &crate::RTSPStream) {
125        self.parent_removed_stream(stream);
126    }
127
128    fn prepared(&self) {
129        self.parent_prepared();
130    }
131
132    fn unprepared(&self) {
133        self.parent_unprepared();
134    }
135
136    fn target_state(&self, state: gst::State) {
137        self.parent_target_state(state);
138    }
139
140    fn new_state(&self, state: gst::State) {
141        self.parent_new_state(state);
142    }
143
144    /// Configure an SDP on `self` for receiving streams
145    /// ## `sdp`
146    /// a `GstSDPMessage`
147    ///
148    /// # Returns
149    ///
150    /// TRUE on success.
151    fn handle_sdp(&self, sdp: &gst_sdp::SDPMessageRef) -> Result<(), gst::LoggableError> {
152        self.parent_handle_sdp(sdp)
153    }
154}
155
156pub trait RTSPMediaImplExt: RTSPMediaImpl {
157    fn parent_handle_message(&self, message: &gst::MessageRef) -> bool {
158        unsafe {
159            let data = Self::type_data();
160            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
161            if let Some(f) = (*parent_class).handle_message {
162                from_glib(f(
163                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
164                    message.as_ptr() as *mut _,
165                ))
166            } else {
167                false
168            }
169        }
170    }
171
172    fn parent_prepare(&self, thread: &RTSPThread) -> Result<(), gst::LoggableError> {
173        unsafe {
174            let data = Self::type_data();
175            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
176            if let Some(f) = (*parent_class).prepare {
177                gst::result_from_gboolean!(
178                    f(
179                        self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
180                        thread.to_glib_none().0
181                    ),
182                    gst::CAT_RUST,
183                    "Parent function `prepare` failed"
184                )
185            } else {
186                Ok(())
187            }
188        }
189    }
190
191    fn parent_unprepare(&self) -> Result<(), gst::LoggableError> {
192        unsafe {
193            let data = Self::type_data();
194            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
195            if let Some(f) = (*parent_class).unprepare {
196                gst::result_from_gboolean!(
197                    f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0),
198                    gst::CAT_RUST,
199                    "Parent function `unprepare` failed"
200                )
201            } else {
202                Ok(())
203            }
204        }
205    }
206
207    fn parent_suspend(&self) -> Result<(), gst::LoggableError> {
208        unsafe {
209            let data = Self::type_data();
210            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
211            if let Some(f) = (*parent_class).suspend {
212                gst::result_from_gboolean!(
213                    f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0),
214                    gst::CAT_RUST,
215                    "Parent function `suspend` failed"
216                )
217            } else {
218                Ok(())
219            }
220        }
221    }
222
223    fn parent_unsuspend(&self) -> Result<(), gst::LoggableError> {
224        unsafe {
225            let data = Self::type_data();
226            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
227            if let Some(f) = (*parent_class).unsuspend {
228                gst::result_from_gboolean!(
229                    f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0),
230                    gst::CAT_RUST,
231                    "Parent function `unsuspend` failed"
232                )
233            } else {
234                Ok(())
235            }
236        }
237    }
238
239    // TODO missing: convert_range
240    fn parent_query_position(&self) -> Option<gst::ClockTime> {
241        unsafe {
242            use std::mem;
243
244            let data = Self::type_data();
245            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
246            if let Some(f) = (*parent_class).query_position {
247                let mut position = mem::MaybeUninit::uninit();
248                if f(
249                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
250                    position.as_mut_ptr(),
251                ) == glib::ffi::GFALSE
252                {
253                    None
254                } else {
255                    from_glib(position.assume_init() as u64)
256                }
257            } else {
258                None
259            }
260        }
261    }
262
263    fn parent_query_stop(&self) -> Option<gst::ClockTime> {
264        unsafe {
265            use std::mem;
266
267            let data = Self::type_data();
268            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
269            if let Some(f) = (*parent_class).query_stop {
270                let mut stop = mem::MaybeUninit::uninit();
271                if f(
272                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
273                    stop.as_mut_ptr(),
274                ) == glib::ffi::GFALSE
275                {
276                    None
277                } else {
278                    from_glib(stop.assume_init() as u64)
279                }
280            } else {
281                None
282            }
283        }
284    }
285
286    fn parent_create_rtpbin(&self) -> Option<gst::Element> {
287        unsafe {
288            let data = Self::type_data();
289            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
290            let f = (*parent_class)
291                .create_rtpbin
292                .expect("No `create_rtpbin` virtual method implementation in parent class");
293
294            from_glib_none(f(self
295                .obj()
296                .unsafe_cast_ref::<RTSPMedia>()
297                .to_glib_none()
298                .0))
299        }
300    }
301
302    fn parent_setup_rtpbin(&self, rtpbin: &gst::Element) -> Result<(), gst::LoggableError> {
303        unsafe {
304            let data = Self::type_data();
305            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
306            if let Some(f) = (*parent_class).setup_rtpbin {
307                let ptr = rtpbin.to_glib_none().0;
308
309                // The C code assumes to pass a floating reference around so let's make sure we do
310                glib::gobject_ffi::g_object_force_floating(ptr as *mut _);
311
312                let res = gst::result_from_gboolean!(
313                    f(
314                        self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
315                        ptr
316                    ),
317                    gst::CAT_RUST,
318                    "Parent function `setup_sdp` failed"
319                );
320
321                // If the code didn't accidentally sink it then we have to do that
322                // here now so that we don't have any floating reference on our side
323                // anymore
324                if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
325                    glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
326                }
327
328                res
329            } else {
330                Ok(())
331            }
332        }
333    }
334
335    fn parent_setup_sdp(
336        &self,
337        sdp: &mut gst_sdp::SDPMessageRef,
338        info: &SDPInfo,
339    ) -> Result<(), gst::LoggableError> {
340        unsafe {
341            let data = Self::type_data();
342            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
343            let f = (*parent_class)
344                .setup_sdp
345                .expect("No `setup_sdp` virtual method implementation in parent class");
346
347            gst::result_from_gboolean!(
348                f(
349                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
350                    sdp as *mut _ as *mut gst_sdp::ffi::GstSDPMessage,
351                    info.0.as_ptr()
352                ),
353                gst::CAT_RUST,
354                "Parent function `setup_sdp` failed"
355            )
356        }
357    }
358
359    fn parent_new_stream(&self, stream: &crate::RTSPStream) {
360        unsafe {
361            let data = Self::type_data();
362            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
363            if let Some(f) = (*parent_class).new_stream {
364                f(
365                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
366                    stream.to_glib_none().0,
367                );
368            }
369        }
370    }
371
372    fn parent_removed_stream(&self, stream: &crate::RTSPStream) {
373        unsafe {
374            let data = Self::type_data();
375            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
376            if let Some(f) = (*parent_class).removed_stream {
377                f(
378                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
379                    stream.to_glib_none().0,
380                );
381            }
382        }
383    }
384
385    fn parent_prepared(&self) {
386        unsafe {
387            let data = Self::type_data();
388            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
389            if let Some(f) = (*parent_class).prepared {
390                f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0);
391            }
392        }
393    }
394
395    fn parent_unprepared(&self) {
396        unsafe {
397            let data = Self::type_data();
398            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
399            if let Some(f) = (*parent_class).unprepared {
400                f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0);
401            }
402        }
403    }
404
405    fn parent_target_state(&self, state: gst::State) {
406        unsafe {
407            let data = Self::type_data();
408            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
409            if let Some(f) = (*parent_class).target_state {
410                f(
411                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
412                    state.into_glib(),
413                );
414            }
415        }
416    }
417
418    fn parent_new_state(&self, state: gst::State) {
419        unsafe {
420            let data = Self::type_data();
421            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
422            if let Some(f) = (*parent_class).new_state {
423                f(
424                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
425                    state.into_glib(),
426                );
427            }
428        }
429    }
430
431    fn parent_handle_sdp(&self, sdp: &gst_sdp::SDPMessageRef) -> Result<(), gst::LoggableError> {
432        unsafe {
433            let data = Self::type_data();
434            let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
435            let f = (*parent_class)
436                .handle_sdp
437                .expect("No `handle_sdp` virtual method implementation in parent class");
438
439            gst::result_from_gboolean!(
440                f(
441                    self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
442                    sdp as *const _ as *mut gst_sdp::ffi::GstSDPMessage
443                ),
444                gst::CAT_RUST,
445                "Parent function `handle_sdp` failed"
446            )
447        }
448    }
449}
450
451impl<T: RTSPMediaImpl> RTSPMediaImplExt for T {}
452
453unsafe impl<T: RTSPMediaImpl> IsSubclassable<T> for RTSPMedia {
454    fn class_init(klass: &mut glib::Class<Self>) {
455        Self::parent_class_init::<T>(klass);
456        let klass = klass.as_mut();
457        klass.handle_message = Some(media_handle_message::<T>);
458        klass.prepare = Some(media_prepare::<T>);
459        klass.unprepare = Some(media_unprepare::<T>);
460        klass.suspend = Some(media_suspend::<T>);
461        klass.unsuspend = Some(media_unsuspend::<T>);
462        klass.query_position = Some(media_query_position::<T>);
463        klass.query_stop = Some(media_query_stop::<T>);
464        klass.create_rtpbin = Some(media_create_rtpbin::<T>);
465        klass.setup_rtpbin = Some(media_setup_rtpbin::<T>);
466        klass.setup_sdp = Some(media_setup_sdp::<T>);
467        klass.new_stream = Some(media_new_stream::<T>);
468        klass.removed_stream = Some(media_removed_stream::<T>);
469        klass.prepared = Some(media_prepared::<T>);
470        klass.unprepared = Some(media_unprepared::<T>);
471        klass.target_state = Some(media_target_state::<T>);
472        klass.new_state = Some(media_new_state::<T>);
473        klass.handle_sdp = Some(media_handle_sdp::<T>);
474    }
475}
476
477unsafe extern "C" fn media_handle_message<T: RTSPMediaImpl>(
478    ptr: *mut ffi::GstRTSPMedia,
479    message: *mut gst::ffi::GstMessage,
480) -> glib::ffi::gboolean {
481    unsafe {
482        let instance = &*(ptr as *mut T::Instance);
483        let imp = instance.imp();
484
485        imp.handle_message(gst::MessageRef::from_ptr(message))
486            .into_glib()
487    }
488}
489
490unsafe extern "C" fn media_prepare<T: RTSPMediaImpl>(
491    ptr: *mut ffi::GstRTSPMedia,
492    thread: *mut ffi::GstRTSPThread,
493) -> glib::ffi::gboolean {
494    unsafe {
495        let instance = &*(ptr as *mut T::Instance);
496        let imp = instance.imp();
497
498        match imp.prepare(&from_glib_borrow(thread)) {
499            Ok(()) => glib::ffi::GTRUE,
500            Err(err) => {
501                err.log_with_imp(imp);
502                glib::ffi::GFALSE
503            }
504        }
505    }
506}
507
508unsafe extern "C" fn media_unprepare<T: RTSPMediaImpl>(
509    ptr: *mut ffi::GstRTSPMedia,
510) -> glib::ffi::gboolean {
511    unsafe {
512        let instance = &*(ptr as *mut T::Instance);
513        let imp = instance.imp();
514
515        match imp.unprepare() {
516            Ok(()) => glib::ffi::GTRUE,
517            Err(err) => {
518                err.log_with_imp(imp);
519                glib::ffi::GFALSE
520            }
521        }
522    }
523}
524
525unsafe extern "C" fn media_suspend<T: RTSPMediaImpl>(
526    ptr: *mut ffi::GstRTSPMedia,
527) -> glib::ffi::gboolean {
528    unsafe {
529        let instance = &*(ptr as *mut T::Instance);
530        let imp = instance.imp();
531
532        match imp.suspend() {
533            Ok(()) => glib::ffi::GTRUE,
534            Err(err) => {
535                err.log_with_imp(imp);
536                glib::ffi::GFALSE
537            }
538        }
539    }
540}
541
542unsafe extern "C" fn media_unsuspend<T: RTSPMediaImpl>(
543    ptr: *mut ffi::GstRTSPMedia,
544) -> glib::ffi::gboolean {
545    unsafe {
546        let instance = &*(ptr as *mut T::Instance);
547        let imp = instance.imp();
548
549        match imp.unsuspend() {
550            Ok(()) => glib::ffi::GTRUE,
551            Err(err) => {
552                err.log_with_imp(imp);
553                glib::ffi::GFALSE
554            }
555        }
556    }
557}
558
559unsafe extern "C" fn media_query_position<T: RTSPMediaImpl>(
560    ptr: *mut ffi::GstRTSPMedia,
561    position: *mut i64,
562) -> glib::ffi::gboolean {
563    unsafe {
564        let instance = &*(ptr as *mut T::Instance);
565        let imp = instance.imp();
566
567        match imp.query_position() {
568            Some(pos) => {
569                *position = pos.into_glib() as i64;
570                glib::ffi::GTRUE
571            }
572            None => glib::ffi::GFALSE,
573        }
574    }
575}
576
577unsafe extern "C" fn media_query_stop<T: RTSPMediaImpl>(
578    ptr: *mut ffi::GstRTSPMedia,
579    stop: *mut i64,
580) -> glib::ffi::gboolean {
581    unsafe {
582        let instance = &*(ptr as *mut T::Instance);
583        let imp = instance.imp();
584
585        match imp.query_stop() {
586            Some(s) => {
587                *stop = s.into_glib() as i64;
588                glib::ffi::GTRUE
589            }
590            None => glib::ffi::GFALSE,
591        }
592    }
593}
594
595unsafe extern "C" fn media_create_rtpbin<T: RTSPMediaImpl>(
596    ptr: *mut ffi::GstRTSPMedia,
597) -> *mut gst::ffi::GstElement {
598    unsafe {
599        let instance = &*(ptr as *mut T::Instance);
600        let imp = instance.imp();
601
602        let res: *mut gst::ffi::GstElement = imp.create_rtpbin().into_glib_ptr();
603
604        if !res.is_null() {
605            glib::gobject_ffi::g_object_force_floating(res as *mut _);
606        }
607
608        res
609    }
610}
611
612unsafe extern "C" fn media_setup_rtpbin<T: RTSPMediaImpl>(
613    ptr: *mut ffi::GstRTSPMedia,
614    rtpbin: *mut gst::ffi::GstElement,
615) -> glib::ffi::gboolean {
616    unsafe {
617        let instance = &*(ptr as *mut T::Instance);
618        let imp = instance.imp();
619
620        // If the rtpbin was floating before make sure it is not anymore for now so
621        // we don't accidentally take ownership of it somewhere along the line
622        if glib::gobject_ffi::g_object_is_floating(rtpbin as *mut _) != glib::ffi::GFALSE {
623            glib::gobject_ffi::g_object_ref_sink(rtpbin as *mut _);
624        }
625
626        let res = match imp.setup_rtpbin(&from_glib_borrow(rtpbin)) {
627            Ok(()) => glib::ffi::GTRUE,
628            Err(err) => {
629                err.log_with_imp(imp);
630                glib::ffi::GFALSE
631            }
632        };
633
634        // Ensure that the rtpbin is still floating afterwards here
635        glib::gobject_ffi::g_object_force_floating(rtpbin as *mut _);
636
637        res
638    }
639}
640
641unsafe extern "C" fn media_setup_sdp<T: RTSPMediaImpl>(
642    ptr: *mut ffi::GstRTSPMedia,
643    sdp: *mut gst_sdp::ffi::GstSDPMessage,
644    info: *mut ffi::GstSDPInfo,
645) -> glib::ffi::gboolean {
646    unsafe {
647        let instance = &*(ptr as *mut T::Instance);
648        let imp = instance.imp();
649
650        match imp.setup_sdp(
651            &mut *(sdp as *mut gst_sdp::SDPMessageRef),
652            &SDPInfo(ptr::NonNull::new(info).expect("NULL SDPInfo")),
653        ) {
654            Ok(()) => glib::ffi::GTRUE,
655            Err(err) => {
656                err.log_with_imp(imp);
657                glib::ffi::GFALSE
658            }
659        }
660    }
661}
662
663unsafe extern "C" fn media_new_stream<T: RTSPMediaImpl>(
664    ptr: *mut ffi::GstRTSPMedia,
665    stream: *mut ffi::GstRTSPStream,
666) {
667    unsafe {
668        let instance = &*(ptr as *mut T::Instance);
669        let imp = instance.imp();
670
671        imp.new_stream(&from_glib_borrow(stream));
672    }
673}
674
675unsafe extern "C" fn media_removed_stream<T: RTSPMediaImpl>(
676    ptr: *mut ffi::GstRTSPMedia,
677    stream: *mut ffi::GstRTSPStream,
678) {
679    unsafe {
680        let instance = &*(ptr as *mut T::Instance);
681        let imp = instance.imp();
682
683        imp.removed_stream(&from_glib_borrow(stream));
684    }
685}
686
687unsafe extern "C" fn media_prepared<T: RTSPMediaImpl>(ptr: *mut ffi::GstRTSPMedia) {
688    unsafe {
689        let instance = &*(ptr as *mut T::Instance);
690        let imp = instance.imp();
691
692        imp.prepared();
693    }
694}
695
696unsafe extern "C" fn media_unprepared<T: RTSPMediaImpl>(ptr: *mut ffi::GstRTSPMedia) {
697    unsafe {
698        let instance = &*(ptr as *mut T::Instance);
699        let imp = instance.imp();
700
701        imp.unprepared();
702    }
703}
704
705unsafe extern "C" fn media_target_state<T: RTSPMediaImpl>(
706    ptr: *mut ffi::GstRTSPMedia,
707    state: gst::ffi::GstState,
708) {
709    unsafe {
710        let instance = &*(ptr as *mut T::Instance);
711        let imp = instance.imp();
712
713        imp.target_state(from_glib(state));
714    }
715}
716
717unsafe extern "C" fn media_new_state<T: RTSPMediaImpl>(
718    ptr: *mut ffi::GstRTSPMedia,
719    state: gst::ffi::GstState,
720) {
721    unsafe {
722        let instance = &*(ptr as *mut T::Instance);
723        let imp = instance.imp();
724
725        imp.new_state(from_glib(state));
726    }
727}
728
729unsafe extern "C" fn media_handle_sdp<T: RTSPMediaImpl>(
730    ptr: *mut ffi::GstRTSPMedia,
731    sdp: *mut gst_sdp::ffi::GstSDPMessage,
732) -> glib::ffi::gboolean {
733    unsafe {
734        let instance = &*(ptr as *mut T::Instance);
735        let imp = instance.imp();
736
737        match imp.handle_sdp(&*(sdp as *const gst_sdp::SDPMessageRef)) {
738            Ok(()) => glib::ffi::GTRUE,
739            Err(err) => {
740                err.log_with_imp(imp);
741                glib::ffi::GFALSE
742            }
743        }
744    }
745}