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