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::{ffi, RTSPMedia, RTSPThread};
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    let instance = &*(ptr as *mut T::Instance);
427    let imp = instance.imp();
428
429    imp.handle_message(gst::MessageRef::from_ptr(message))
430        .into_glib()
431}
432
433unsafe extern "C" fn media_prepare<T: RTSPMediaImpl>(
434    ptr: *mut ffi::GstRTSPMedia,
435    thread: *mut ffi::GstRTSPThread,
436) -> glib::ffi::gboolean {
437    let instance = &*(ptr as *mut T::Instance);
438    let imp = instance.imp();
439
440    match imp.prepare(&from_glib_borrow(thread)) {
441        Ok(()) => glib::ffi::GTRUE,
442        Err(err) => {
443            err.log_with_imp(imp);
444            glib::ffi::GFALSE
445        }
446    }
447}
448
449unsafe extern "C" fn media_unprepare<T: RTSPMediaImpl>(
450    ptr: *mut ffi::GstRTSPMedia,
451) -> glib::ffi::gboolean {
452    let instance = &*(ptr as *mut T::Instance);
453    let imp = instance.imp();
454
455    match imp.unprepare() {
456        Ok(()) => glib::ffi::GTRUE,
457        Err(err) => {
458            err.log_with_imp(imp);
459            glib::ffi::GFALSE
460        }
461    }
462}
463
464unsafe extern "C" fn media_suspend<T: RTSPMediaImpl>(
465    ptr: *mut ffi::GstRTSPMedia,
466) -> glib::ffi::gboolean {
467    let instance = &*(ptr as *mut T::Instance);
468    let imp = instance.imp();
469
470    match imp.suspend() {
471        Ok(()) => glib::ffi::GTRUE,
472        Err(err) => {
473            err.log_with_imp(imp);
474            glib::ffi::GFALSE
475        }
476    }
477}
478
479unsafe extern "C" fn media_unsuspend<T: RTSPMediaImpl>(
480    ptr: *mut ffi::GstRTSPMedia,
481) -> glib::ffi::gboolean {
482    let instance = &*(ptr as *mut T::Instance);
483    let imp = instance.imp();
484
485    match imp.unsuspend() {
486        Ok(()) => glib::ffi::GTRUE,
487        Err(err) => {
488            err.log_with_imp(imp);
489            glib::ffi::GFALSE
490        }
491    }
492}
493
494unsafe extern "C" fn media_query_position<T: RTSPMediaImpl>(
495    ptr: *mut ffi::GstRTSPMedia,
496    position: *mut i64,
497) -> glib::ffi::gboolean {
498    let instance = &*(ptr as *mut T::Instance);
499    let imp = instance.imp();
500
501    match imp.query_position() {
502        Some(pos) => {
503            *position = pos.into_glib() as i64;
504            glib::ffi::GTRUE
505        }
506        None => glib::ffi::GFALSE,
507    }
508}
509
510unsafe extern "C" fn media_query_stop<T: RTSPMediaImpl>(
511    ptr: *mut ffi::GstRTSPMedia,
512    stop: *mut i64,
513) -> glib::ffi::gboolean {
514    let instance = &*(ptr as *mut T::Instance);
515    let imp = instance.imp();
516
517    match imp.query_stop() {
518        Some(s) => {
519            *stop = s.into_glib() as i64;
520            glib::ffi::GTRUE
521        }
522        None => glib::ffi::GFALSE,
523    }
524}
525
526unsafe extern "C" fn media_create_rtpbin<T: RTSPMediaImpl>(
527    ptr: *mut ffi::GstRTSPMedia,
528) -> *mut gst::ffi::GstElement {
529    let instance = &*(ptr as *mut T::Instance);
530    let imp = instance.imp();
531
532    let res: *mut gst::ffi::GstElement = imp.create_rtpbin().into_glib_ptr();
533
534    if !res.is_null() {
535        glib::gobject_ffi::g_object_force_floating(res as *mut _);
536    }
537
538    res
539}
540
541unsafe extern "C" fn media_setup_rtpbin<T: RTSPMediaImpl>(
542    ptr: *mut ffi::GstRTSPMedia,
543    rtpbin: *mut gst::ffi::GstElement,
544) -> glib::ffi::gboolean {
545    let instance = &*(ptr as *mut T::Instance);
546    let imp = instance.imp();
547
548    // If the rtpbin was floating before make sure it is not anymore for now so
549    // we don't accidentally take ownership of it somewhere along the line
550    if glib::gobject_ffi::g_object_is_floating(rtpbin as *mut _) != glib::ffi::GFALSE {
551        glib::gobject_ffi::g_object_ref_sink(rtpbin as *mut _);
552    }
553
554    let res = match imp.setup_rtpbin(&from_glib_borrow(rtpbin)) {
555        Ok(()) => glib::ffi::GTRUE,
556        Err(err) => {
557            err.log_with_imp(imp);
558            glib::ffi::GFALSE
559        }
560    };
561
562    // Ensure that the rtpbin is still floating afterwards here
563    glib::gobject_ffi::g_object_force_floating(rtpbin as *mut _);
564
565    res
566}
567
568unsafe extern "C" fn media_setup_sdp<T: RTSPMediaImpl>(
569    ptr: *mut ffi::GstRTSPMedia,
570    sdp: *mut gst_sdp::ffi::GstSDPMessage,
571    info: *mut ffi::GstSDPInfo,
572) -> glib::ffi::gboolean {
573    let instance = &*(ptr as *mut T::Instance);
574    let imp = instance.imp();
575
576    match imp.setup_sdp(
577        &mut *(sdp as *mut gst_sdp::SDPMessageRef),
578        &SDPInfo(ptr::NonNull::new(info).expect("NULL SDPInfo")),
579    ) {
580        Ok(()) => glib::ffi::GTRUE,
581        Err(err) => {
582            err.log_with_imp(imp);
583            glib::ffi::GFALSE
584        }
585    }
586}
587
588unsafe extern "C" fn media_new_stream<T: RTSPMediaImpl>(
589    ptr: *mut ffi::GstRTSPMedia,
590    stream: *mut ffi::GstRTSPStream,
591) {
592    let instance = &*(ptr as *mut T::Instance);
593    let imp = instance.imp();
594
595    imp.new_stream(&from_glib_borrow(stream));
596}
597
598unsafe extern "C" fn media_removed_stream<T: RTSPMediaImpl>(
599    ptr: *mut ffi::GstRTSPMedia,
600    stream: *mut ffi::GstRTSPStream,
601) {
602    let instance = &*(ptr as *mut T::Instance);
603    let imp = instance.imp();
604
605    imp.removed_stream(&from_glib_borrow(stream));
606}
607
608unsafe extern "C" fn media_prepared<T: RTSPMediaImpl>(ptr: *mut ffi::GstRTSPMedia) {
609    let instance = &*(ptr as *mut T::Instance);
610    let imp = instance.imp();
611
612    imp.prepared();
613}
614
615unsafe extern "C" fn media_unprepared<T: RTSPMediaImpl>(ptr: *mut ffi::GstRTSPMedia) {
616    let instance = &*(ptr as *mut T::Instance);
617    let imp = instance.imp();
618
619    imp.unprepared();
620}
621
622unsafe extern "C" fn media_target_state<T: RTSPMediaImpl>(
623    ptr: *mut ffi::GstRTSPMedia,
624    state: gst::ffi::GstState,
625) {
626    let instance = &*(ptr as *mut T::Instance);
627    let imp = instance.imp();
628
629    imp.target_state(from_glib(state));
630}
631
632unsafe extern "C" fn media_new_state<T: RTSPMediaImpl>(
633    ptr: *mut ffi::GstRTSPMedia,
634    state: gst::ffi::GstState,
635) {
636    let instance = &*(ptr as *mut T::Instance);
637    let imp = instance.imp();
638
639    imp.new_state(from_glib(state));
640}
641
642unsafe extern "C" fn media_handle_sdp<T: RTSPMediaImpl>(
643    ptr: *mut ffi::GstRTSPMedia,
644    sdp: *mut gst_sdp::ffi::GstSDPMessage,
645) -> glib::ffi::gboolean {
646    let instance = &*(ptr as *mut T::Instance);
647    let imp = instance.imp();
648
649    match imp.handle_sdp(&*(sdp as *const gst_sdp::SDPMessageRef)) {
650        Ok(()) => glib::ffi::GTRUE,
651        Err(err) => {
652            err.log_with_imp(imp);
653            glib::ffi::GFALSE
654        }
655    }
656}