gstreamer_sdp/
sdp_message.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4    borrow::{Borrow, BorrowMut, ToOwned},
5    ffi::CStr,
6    fmt, mem, ops, ptr,
7};
8
9use glib::{prelude::*, translate::*};
10
11use crate::{
12    ffi,
13    sdp_attribute::SDPAttribute,
14    sdp_bandwidth::SDPBandwidth,
15    sdp_connection::SDPConnection,
16    sdp_key::SDPKey,
17    sdp_media::{SDPMedia, SDPMediaRef},
18    sdp_origin::SDPOrigin,
19    sdp_time::SDPTime,
20    sdp_zone::SDPZone,
21};
22
23glib::wrapper! {
24    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
25    #[doc(alias = "GstSDPMessage")]
26    pub struct SDPMessage(Boxed<ffi::GstSDPMessage>);
27
28    match fn {
29        copy => |ptr| {
30            let mut copy = std::ptr::null_mut();
31            let res = ffi::gst_sdp_message_copy(ptr, &mut copy);
32            debug_assert_eq!(res, ffi::GST_SDP_OK);
33            copy
34        },
35        free => |ptr| {
36            let res = ffi::gst_sdp_message_free(ptr);
37            debug_assert_eq!(res, ffi::GST_SDP_OK);
38        },
39        type_ => || ffi::gst_sdp_message_get_type(),
40    }
41}
42
43unsafe impl Send for SDPMessage {}
44unsafe impl Sync for SDPMessage {}
45
46impl Default for SDPMessage {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52impl ops::Deref for SDPMessage {
53    type Target = SDPMessageRef;
54
55    fn deref(&self) -> &SDPMessageRef {
56        unsafe { &*(self.as_ptr() as *const SDPMessageRef) }
57    }
58}
59
60impl ops::DerefMut for SDPMessage {
61    fn deref_mut(&mut self) -> &mut SDPMessageRef {
62        unsafe { &mut *(self.to_glib_none_mut().0 as *mut SDPMessageRef) }
63    }
64}
65
66impl fmt::Debug for SDPMessage {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        <SDPMessageRef as fmt::Debug>::fmt(self, f)
69    }
70}
71
72impl fmt::Display for SDPMessage {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        <SDPMessageRef as fmt::Display>::fmt(self, f)
75    }
76}
77
78impl SDPMessage {
79    #[doc(alias = "gst_sdp_message_new")]
80    pub fn new() -> SDPMessage {
81        assert_initialized_main_thread!();
82        unsafe {
83            let mut msg = ptr::null_mut();
84            ffi::gst_sdp_message_new(&mut msg);
85            from_glib_full(msg)
86        }
87    }
88
89    #[doc(alias = "gst_sdp_message_parse_buffer")]
90    pub fn parse_buffer(data: &[u8]) -> Result<Self, glib::BoolError> {
91        assert_initialized_main_thread!();
92        unsafe {
93            let size = data.len() as u32;
94            let mut msg = ptr::null_mut();
95            ffi::gst_sdp_message_new(&mut msg);
96            let result = ffi::gst_sdp_message_parse_buffer(data.to_glib_none().0, size, msg);
97            match result {
98                ffi::GST_SDP_OK => Ok(from_glib_full(msg)),
99                _ => {
100                    ffi::gst_sdp_message_uninit(msg);
101                    Err(glib::bool_error!("Failed to parse buffer"))
102                }
103            }
104        }
105    }
106
107    #[doc(alias = "gst_sdp_message_parse_uri")]
108    pub fn parse_uri(uri: &str) -> Result<Self, glib::BoolError> {
109        assert_initialized_main_thread!();
110        unsafe {
111            let mut msg = ptr::null_mut();
112            ffi::gst_sdp_message_new(&mut msg);
113            let result = ffi::gst_sdp_message_parse_uri(uri.to_glib_none().0, msg);
114            match result {
115                ffi::GST_SDP_OK => Ok(from_glib_full(msg)),
116                _ => {
117                    ffi::gst_sdp_message_uninit(msg);
118                    Err(glib::bool_error!("Failed to parse URI"))
119                }
120            }
121        }
122    }
123}
124
125#[repr(transparent)]
126#[doc(alias = "GstSDPMessage")]
127pub struct SDPMessageRef(ffi::GstSDPMessage);
128
129impl fmt::Debug for SDPMessageRef {
130    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
131        use std::cell::RefCell;
132
133        struct DebugIter<I>(RefCell<I>);
134        impl<I: Iterator> fmt::Debug for DebugIter<I>
135        where
136            I::Item: fmt::Debug,
137        {
138            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139                f.debug_list().entries(&mut *self.0.borrow_mut()).finish()
140            }
141        }
142
143        f.debug_struct("SDPMessage")
144            .field("connection", &self.connection())
145            .field("information", &self.information())
146            .field("key", &self.key())
147            .field("origin", &self.origin())
148            .field("session-name", &self.session_name())
149            .field("uri", &self.uri())
150            .field("version", &self.version())
151            .field("attributes", &DebugIter(RefCell::new(self.attributes())))
152            .field("bandwidths", &DebugIter(RefCell::new(self.bandwidths())))
153            .field("emails", &DebugIter(RefCell::new(self.emails())))
154            .field("medias", &DebugIter(RefCell::new(self.medias())))
155            .field("phones", &DebugIter(RefCell::new(self.phones())))
156            .field("times", &DebugIter(RefCell::new(self.times())))
157            .field("zones", &DebugIter(RefCell::new(self.zones())))
158            .finish()
159    }
160}
161
162impl fmt::Display for SDPMessageRef {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        match self.as_text() {
165            Ok(text) => f.write_str(text.as_str()),
166            Err(_) => Err(fmt::Error),
167        }
168    }
169}
170
171unsafe impl Send for SDPMessageRef {}
172unsafe impl Sync for SDPMessageRef {}
173
174impl SDPMessageRef {
175    #[doc(alias = "gst_sdp_message_add_attribute")]
176    pub fn add_attribute(&mut self, key: &str, value: Option<&str>) {
177        unsafe {
178            ffi::gst_sdp_message_add_attribute(
179                &mut self.0,
180                key.to_glib_none().0,
181                value.to_glib_none().0,
182            );
183        }
184    }
185
186    #[doc(alias = "gst_sdp_message_add_email")]
187    pub fn add_email(&mut self, email: &str) {
188        unsafe { ffi::gst_sdp_message_add_email(&mut self.0, email.to_glib_none().0) };
189    }
190
191    #[doc(alias = "gst_sdp_message_add_media")]
192    pub fn add_media(&mut self, media: SDPMedia) {
193        unsafe {
194            ffi::gst_sdp_message_add_media(&mut self.0, media.as_ptr());
195        }
196    }
197
198    #[doc(alias = "gst_sdp_message_add_phone")]
199    pub fn add_phone(&mut self, phone: &str) {
200        unsafe { ffi::gst_sdp_message_add_phone(&mut self.0, phone.to_glib_none().0) };
201    }
202
203    #[doc(alias = "gst_sdp_message_add_time")]
204    pub fn add_time(&mut self, start: &str, stop: &str, repeat: &[&str]) {
205        unsafe {
206            ffi::gst_sdp_message_add_time(
207                &mut self.0,
208                start.to_glib_none().0,
209                stop.to_glib_none().0,
210                repeat.to_glib_none().0,
211            )
212        };
213    }
214
215    #[doc(alias = "gst_sdp_message_add_zone")]
216    pub fn add_zone(&mut self, adj_time: &str, typed_time: &str) {
217        unsafe {
218            ffi::gst_sdp_message_add_zone(
219                &mut self.0,
220                adj_time.to_glib_none().0,
221                typed_time.to_glib_none().0,
222            )
223        };
224    }
225
226    #[doc(alias = "gst_sdp_message_as_text")]
227    pub fn as_text(&self) -> Result<String, glib::error::BoolError> {
228        unsafe {
229            match from_glib_full(ffi::gst_sdp_message_as_text(&self.0)) {
230                Some(s) => Ok(s),
231                None => Err(glib::bool_error!(
232                    "Failed to convert the contents of message to a text string"
233                )),
234            }
235        }
236    }
237
238    #[doc(alias = "gst_sdp_message_attributes_len")]
239    pub fn attributes_len(&self) -> u32 {
240        unsafe { ffi::gst_sdp_message_attributes_len(&self.0) }
241    }
242
243    #[doc(alias = "gst_sdp_message_attributes_to_caps")]
244    pub fn attributes_to_caps(&self, caps: &mut gst::CapsRef) -> Result<(), glib::BoolError> {
245        let result = unsafe { ffi::gst_sdp_message_attributes_to_caps(&self.0, caps.as_mut_ptr()) };
246        match result {
247            ffi::GST_SDP_OK => Ok(()),
248            _ => Err(glib::bool_error!("Failed to store attributes in caps")),
249        }
250    }
251
252    #[doc(alias = "gst_sdp_message_bandwidths_len")]
253    pub fn bandwidths_len(&self) -> u32 {
254        unsafe { ffi::gst_sdp_message_bandwidths_len(&self.0) }
255    }
256
257    #[doc(alias = "gst_sdp_message_dump")]
258    pub fn dump(&self) {
259        unsafe { ffi::gst_sdp_message_dump(&self.0) };
260    }
261
262    #[doc(alias = "gst_sdp_message_emails_len")]
263    pub fn emails_len(&self) -> u32 {
264        unsafe { ffi::gst_sdp_message_emails_len(&self.0) }
265    }
266
267    #[doc(alias = "get_attribute")]
268    #[doc(alias = "gst_sdp_message_get_attribute")]
269    pub fn attribute(&self, idx: u32) -> Option<&SDPAttribute> {
270        if idx >= self.attributes_len() {
271            return None;
272        }
273
274        unsafe {
275            let ptr = ffi::gst_sdp_message_get_attribute(&self.0, idx);
276            if ptr.is_null() {
277                None
278            } else {
279                Some(&*(ptr as *mut SDPAttribute))
280            }
281        }
282    }
283
284    #[doc(alias = "get_attribute_val")]
285    #[doc(alias = "gst_sdp_message_get_attribute_val")]
286    pub fn attribute_val(&self, key: &str) -> Option<&str> {
287        unsafe {
288            let ptr = ffi::gst_sdp_message_get_attribute_val(&self.0, key.to_glib_none().0);
289            if ptr.is_null() {
290                None
291            } else {
292                CStr::from_ptr(ptr).to_str().ok()
293            }
294        }
295    }
296
297    #[doc(alias = "get_attribute_val_n")]
298    #[doc(alias = "gst_sdp_message_get_attribute_val_n")]
299    pub fn attribute_val_n(&self, key: &str, nth: u32) -> Option<&str> {
300        unsafe {
301            let ptr = ffi::gst_sdp_message_get_attribute_val_n(&self.0, key.to_glib_none().0, nth);
302            if ptr.is_null() {
303                None
304            } else {
305                CStr::from_ptr(ptr).to_str().ok()
306            }
307        }
308    }
309
310    #[doc(alias = "get_bandwidth")]
311    #[doc(alias = "gst_sdp_message_get_bandwidth")]
312    pub fn bandwidth(&self, idx: u32) -> Option<&SDPBandwidth> {
313        if idx >= self.bandwidths_len() {
314            return None;
315        }
316
317        unsafe {
318            let ptr = ffi::gst_sdp_message_get_bandwidth(&self.0, idx);
319            if ptr.is_null() {
320                None
321            } else {
322                Some(&*(ptr as *mut SDPBandwidth))
323            }
324        }
325    }
326
327    #[doc(alias = "get_connection")]
328    #[doc(alias = "gst_sdp_message_get_connection")]
329    pub fn connection(&self) -> Option<&SDPConnection> {
330        unsafe {
331            let ptr = ffi::gst_sdp_message_get_connection(&self.0);
332            if ptr.is_null() {
333                None
334            } else {
335                Some(&*(ptr as *mut SDPConnection))
336            }
337        }
338    }
339
340    #[doc(alias = "get_email")]
341    #[doc(alias = "gst_sdp_message_get_email")]
342    pub fn email(&self, idx: u32) -> Option<&str> {
343        if idx >= self.emails_len() {
344            return None;
345        }
346
347        unsafe {
348            let ptr = ffi::gst_sdp_message_get_email(&self.0, idx);
349            if ptr.is_null() {
350                None
351            } else {
352                CStr::from_ptr(ptr).to_str().ok()
353            }
354        }
355    }
356
357    #[doc(alias = "get_information")]
358    #[doc(alias = "gst_sdp_message_get_information")]
359    pub fn information(&self) -> Option<&str> {
360        unsafe {
361            let ptr = ffi::gst_sdp_message_get_information(&self.0);
362            if ptr.is_null() {
363                None
364            } else {
365                CStr::from_ptr(ptr).to_str().ok()
366            }
367        }
368    }
369
370    #[doc(alias = "get_key")]
371    #[doc(alias = "gst_sdp_message_get_key")]
372    pub fn key(&self) -> Option<&SDPKey> {
373        unsafe {
374            let ptr = ffi::gst_sdp_message_get_key(&self.0);
375            if ptr.is_null() {
376                None
377            } else {
378                Some(&*(ptr as *mut SDPKey))
379            }
380        }
381    }
382
383    #[doc(alias = "get_media")]
384    #[doc(alias = "gst_sdp_message_get_media")]
385    pub fn media(&self, idx: u32) -> Option<&SDPMediaRef> {
386        if idx >= self.medias_len() {
387            return None;
388        }
389
390        unsafe {
391            let ptr = ffi::gst_sdp_message_get_media(&self.0, idx);
392            if ptr.is_null() {
393                None
394            } else {
395                Some(&*(ptr as *const SDPMediaRef))
396            }
397        }
398    }
399
400    #[doc(alias = "get_media_mut")]
401    pub fn media_mut(&mut self, idx: u32) -> Option<&mut SDPMediaRef> {
402        if idx >= self.medias_len() {
403            return None;
404        }
405
406        unsafe {
407            let ptr = ffi::gst_sdp_message_get_media(&self.0, idx);
408            if ptr.is_null() {
409                None
410            } else {
411                Some(&mut *(ptr as *mut SDPMediaRef))
412            }
413        }
414    }
415
416    #[doc(alias = "get_origin")]
417    #[doc(alias = "gst_sdp_message_get_origin")]
418    pub fn origin(&self) -> Option<&SDPOrigin> {
419        unsafe {
420            let ptr = ffi::gst_sdp_message_get_origin(&self.0);
421            if ptr.is_null() {
422                None
423            } else {
424                Some(&*(ptr as *mut SDPOrigin))
425            }
426        }
427    }
428
429    #[doc(alias = "get_phone")]
430    #[doc(alias = "gst_sdp_message_get_phone")]
431    pub fn phone(&self, idx: u32) -> Option<&str> {
432        if idx >= self.phones_len() {
433            return None;
434        }
435
436        unsafe {
437            let ptr = ffi::gst_sdp_message_get_phone(&self.0, idx);
438            if ptr.is_null() {
439                None
440            } else {
441                CStr::from_ptr(ptr).to_str().ok()
442            }
443        }
444    }
445
446    #[doc(alias = "get_session_name")]
447    #[doc(alias = "gst_sdp_message_get_session_name")]
448    pub fn session_name(&self) -> Option<&str> {
449        unsafe {
450            let ptr = ffi::gst_sdp_message_get_session_name(&self.0);
451            if ptr.is_null() {
452                None
453            } else {
454                CStr::from_ptr(ptr).to_str().ok()
455            }
456        }
457    }
458
459    #[doc(alias = "get_time")]
460    #[doc(alias = "gst_sdp_message_get_time")]
461    pub fn time(&self, idx: u32) -> Option<&SDPTime> {
462        if idx >= self.times_len() {
463            return None;
464        }
465
466        unsafe {
467            let ptr = ffi::gst_sdp_message_get_time(&self.0, idx);
468            if ptr.is_null() {
469                None
470            } else {
471                Some(&*(ptr as *mut SDPTime))
472            }
473        }
474    }
475
476    #[doc(alias = "get_uri")]
477    #[doc(alias = "gst_sdp_message_get_uri")]
478    pub fn uri(&self) -> Option<&str> {
479        unsafe {
480            let ptr = ffi::gst_sdp_message_get_uri(&self.0);
481            if ptr.is_null() {
482                None
483            } else {
484                CStr::from_ptr(ptr).to_str().ok()
485            }
486        }
487    }
488
489    #[doc(alias = "get_version")]
490    #[doc(alias = "gst_sdp_message_get_version")]
491    pub fn version(&self) -> Option<&str> {
492        unsafe {
493            let ptr = ffi::gst_sdp_message_get_version(&self.0);
494            if ptr.is_null() {
495                None
496            } else {
497                CStr::from_ptr(ptr).to_str().ok()
498            }
499        }
500    }
501
502    #[doc(alias = "get_zone")]
503    #[doc(alias = "gst_sdp_message_get_zone")]
504    pub fn zone(&self, idx: u32) -> Option<&SDPZone> {
505        if idx >= self.zones_len() {
506            return None;
507        }
508
509        unsafe {
510            let ptr = ffi::gst_sdp_message_get_zone(&self.0, idx);
511            if ptr.is_null() {
512                None
513            } else {
514                Some(&*(ptr as *mut SDPZone))
515            }
516        }
517    }
518
519    #[doc(alias = "gst_sdp_message_insert_attribute")]
520    pub fn insert_attribute(
521        &mut self,
522        idx: Option<u32>,
523        attr: SDPAttribute,
524    ) -> Result<(), glib::BoolError> {
525        if let Some(idx) = idx {
526            if idx >= self.attributes_len() {
527                return Err(glib::bool_error!("Failed to insert attribute"));
528            }
529        }
530
531        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
532        let mut attr = mem::ManuallyDrop::new(attr);
533        let result =
534            unsafe { ffi::gst_sdp_message_insert_attribute(&mut self.0, idx, &mut attr.0) };
535        match result {
536            ffi::GST_SDP_OK => Ok(()),
537            _ => Err(glib::bool_error!("Failed to insert attribute")),
538        }
539    }
540
541    #[doc(alias = "gst_sdp_message_insert_bandwidth")]
542    pub fn insert_bandwidth(
543        &mut self,
544        idx: Option<u32>,
545        bw: SDPBandwidth,
546    ) -> Result<(), glib::BoolError> {
547        if let Some(idx) = idx {
548            if idx >= self.bandwidths_len() {
549                return Err(glib::bool_error!("Failed to insert bandwidth"));
550            }
551        }
552
553        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
554        let mut bw = mem::ManuallyDrop::new(bw);
555        let result = unsafe { ffi::gst_sdp_message_insert_bandwidth(&mut self.0, idx, &mut bw.0) };
556        match result {
557            ffi::GST_SDP_OK => Ok(()),
558            _ => Err(glib::bool_error!("Failed to insert bandwidth")),
559        }
560    }
561
562    #[doc(alias = "gst_sdp_message_insert_email")]
563    pub fn insert_email(&mut self, idx: Option<u32>, email: &str) -> Result<(), glib::BoolError> {
564        if let Some(idx) = idx {
565            if idx >= self.emails_len() {
566                return Err(glib::bool_error!("Failed to insert email"));
567            }
568        }
569
570        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
571        let result =
572            unsafe { ffi::gst_sdp_message_insert_email(&mut self.0, idx, email.to_glib_none().0) };
573        match result {
574            ffi::GST_SDP_OK => Ok(()),
575            _ => Err(glib::bool_error!("Failed to insert email")),
576        }
577    }
578
579    #[doc(alias = "gst_sdp_message_insert_phone")]
580    pub fn insert_phone(&mut self, idx: Option<u32>, phone: &str) -> Result<(), glib::BoolError> {
581        if let Some(idx) = idx {
582            if idx >= self.phones_len() {
583                return Err(glib::bool_error!("Failed to insert phone"));
584            }
585        }
586
587        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
588        let result =
589            unsafe { ffi::gst_sdp_message_insert_phone(&mut self.0, idx, phone.to_glib_none().0) };
590        match result {
591            ffi::GST_SDP_OK => Ok(()),
592            _ => Err(glib::bool_error!("Failed to insert phone")),
593        }
594    }
595
596    #[doc(alias = "gst_sdp_message_insert_time")]
597    pub fn insert_time(&mut self, idx: Option<u32>, time: SDPTime) -> Result<(), glib::BoolError> {
598        if let Some(idx) = idx {
599            if idx >= self.times_len() {
600                return Err(glib::bool_error!("Failed to insert time"));
601            }
602        }
603
604        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
605        let mut time = mem::ManuallyDrop::new(time);
606        let result = unsafe { ffi::gst_sdp_message_insert_time(&mut self.0, idx, &mut time.0) };
607        match result {
608            ffi::GST_SDP_OK => Ok(()),
609            _ => Err(glib::bool_error!("Failed to insert time")),
610        }
611    }
612
613    #[doc(alias = "gst_sdp_message_insert_zone")]
614    pub fn insert_zone(&mut self, idx: Option<u32>, zone: SDPZone) -> Result<(), glib::BoolError> {
615        if let Some(idx) = idx {
616            if idx >= self.zones_len() {
617                return Err(glib::bool_error!("Failed to insert zone"));
618            }
619        }
620
621        let idx = idx.map(|idx| idx as i32).unwrap_or(-1);
622        let mut zone = mem::ManuallyDrop::new(zone);
623        let result = unsafe { ffi::gst_sdp_message_insert_zone(&mut self.0, idx, &mut zone.0) };
624        match result {
625            ffi::GST_SDP_OK => Ok(()),
626            _ => Err(glib::bool_error!("Failed to insert zone")),
627        }
628    }
629
630    #[doc(alias = "gst_sdp_message_medias_len")]
631    pub fn medias_len(&self) -> u32 {
632        unsafe { ffi::gst_sdp_message_medias_len(&self.0) }
633    }
634
635    #[doc(alias = "gst_sdp_message_phones_len")]
636    pub fn phones_len(&self) -> u32 {
637        unsafe { ffi::gst_sdp_message_phones_len(&self.0) }
638    }
639
640    #[doc(alias = "gst_sdp_message_remove_attribute")]
641    pub fn remove_attribute(&mut self, idx: u32) -> Result<(), glib::BoolError> {
642        if idx >= self.attributes_len() {
643            return Err(glib::bool_error!("Failed to remove attribute"));
644        }
645
646        let result = unsafe { ffi::gst_sdp_message_remove_attribute(&mut self.0, idx) };
647        match result {
648            ffi::GST_SDP_OK => Ok(()),
649            _ => Err(glib::bool_error!("Failed to remove attribute")),
650        }
651    }
652
653    #[doc(alias = "gst_sdp_message_remove_bandwidth")]
654    pub fn remove_bandwidth(&mut self, idx: u32) -> Result<(), glib::BoolError> {
655        if idx >= self.bandwidths_len() {
656            return Err(glib::bool_error!("Failed to remove bandwidth"));
657        }
658
659        let result = unsafe { ffi::gst_sdp_message_remove_bandwidth(&mut self.0, idx) };
660        match result {
661            ffi::GST_SDP_OK => Ok(()),
662            _ => Err(glib::bool_error!("Failed to remove bandwidth")),
663        }
664    }
665
666    #[doc(alias = "gst_sdp_message_remove_email")]
667    pub fn remove_email(&mut self, idx: u32) -> Result<(), glib::BoolError> {
668        if idx >= self.emails_len() {
669            return Err(glib::bool_error!("Failed to remove email"));
670        }
671
672        let result = unsafe { ffi::gst_sdp_message_remove_email(&mut self.0, idx) };
673        match result {
674            ffi::GST_SDP_OK => Ok(()),
675            _ => Err(glib::bool_error!("Failed to remove email")),
676        }
677    }
678
679    #[doc(alias = "gst_sdp_message_remove_phone")]
680    pub fn remove_phone(&mut self, idx: u32) -> Result<(), glib::BoolError> {
681        if idx >= self.phones_len() {
682            return Err(glib::bool_error!("Failed to remove phone"));
683        }
684
685        let result = unsafe { ffi::gst_sdp_message_remove_phone(&mut self.0, idx) };
686        match result {
687            ffi::GST_SDP_OK => Ok(()),
688            _ => Err(glib::bool_error!("Failed to remove phone")),
689        }
690    }
691
692    #[doc(alias = "gst_sdp_message_remove_time")]
693    pub fn remove_time(&mut self, idx: u32) -> Result<(), glib::BoolError> {
694        if idx >= self.times_len() {
695            return Err(glib::bool_error!("Failed to remove time"));
696        }
697
698        let result = unsafe { ffi::gst_sdp_message_remove_time(&mut self.0, idx) };
699        match result {
700            ffi::GST_SDP_OK => Ok(()),
701            _ => Err(glib::bool_error!("Failed to remove time")),
702        }
703    }
704
705    #[doc(alias = "gst_sdp_message_remove_zone")]
706    pub fn remove_zone(&mut self, idx: u32) -> Result<(), glib::BoolError> {
707        if idx >= self.zones_len() {
708            return Err(glib::bool_error!("Failed to remove zone"));
709        }
710
711        let result = unsafe { ffi::gst_sdp_message_remove_zone(&mut self.0, idx) };
712        match result {
713            ffi::GST_SDP_OK => Ok(()),
714            _ => Err(glib::bool_error!("Failed to remove zone")),
715        }
716    }
717
718    #[doc(alias = "gst_sdp_message_replace_attribute")]
719    pub fn replace_attribute(
720        &mut self,
721        idx: u32,
722        attr: SDPAttribute,
723    ) -> Result<(), glib::BoolError> {
724        if idx >= self.attributes_len() {
725            return Err(glib::bool_error!("Failed to replace attribute"));
726        }
727
728        let mut attr = mem::ManuallyDrop::new(attr);
729        let result =
730            unsafe { ffi::gst_sdp_message_replace_attribute(&mut self.0, idx, &mut attr.0) };
731        match result {
732            ffi::GST_SDP_OK => Ok(()),
733            _ => Err(glib::bool_error!("Failed to replace attribute")),
734        }
735    }
736
737    #[doc(alias = "gst_sdp_message_replace_bandwidth")]
738    pub fn replace_bandwidth(&mut self, idx: u32, bw: SDPBandwidth) -> Result<(), glib::BoolError> {
739        if idx >= self.bandwidths_len() {
740            return Err(glib::bool_error!("Failed to replace bandwidth"));
741        }
742
743        let mut bw = mem::ManuallyDrop::new(bw);
744        let result = unsafe { ffi::gst_sdp_message_replace_bandwidth(&mut self.0, idx, &mut bw.0) };
745        match result {
746            ffi::GST_SDP_OK => Ok(()),
747            _ => Err(glib::bool_error!("Failed to replace bandwidth")),
748        }
749    }
750
751    #[doc(alias = "gst_sdp_message_replace_email")]
752    pub fn replace_email(&mut self, idx: u32, email: &str) -> Result<(), glib::BoolError> {
753        if idx >= self.emails_len() {
754            return Err(glib::bool_error!("Failed to replace email"));
755        }
756
757        let result =
758            unsafe { ffi::gst_sdp_message_replace_email(&mut self.0, idx, email.to_glib_none().0) };
759        match result {
760            ffi::GST_SDP_OK => Ok(()),
761            _ => Err(glib::bool_error!("Failed to replace email")),
762        }
763    }
764
765    #[doc(alias = "gst_sdp_message_replace_phone")]
766    pub fn replace_phone(&mut self, idx: u32, phone: &str) -> Result<(), glib::BoolError> {
767        if idx >= self.phones_len() {
768            return Err(glib::bool_error!("Failed to replace phone"));
769        }
770
771        let result =
772            unsafe { ffi::gst_sdp_message_replace_phone(&mut self.0, idx, phone.to_glib_none().0) };
773        match result {
774            ffi::GST_SDP_OK => Ok(()),
775            _ => Err(glib::bool_error!("Failed to replace phone")),
776        }
777    }
778
779    #[doc(alias = "gst_sdp_message_replace_time")]
780    pub fn replace_time(&mut self, idx: u32, time: SDPTime) -> Result<(), glib::BoolError> {
781        if idx >= self.times_len() {
782            return Err(glib::bool_error!("Failed to replace time"));
783        }
784
785        let mut time = mem::ManuallyDrop::new(time);
786        let result = unsafe { ffi::gst_sdp_message_replace_time(&mut self.0, idx, &mut time.0) };
787        match result {
788            ffi::GST_SDP_OK => Ok(()),
789            _ => Err(glib::bool_error!("Failed to replace time")),
790        }
791    }
792
793    #[doc(alias = "gst_sdp_message_replace_zone")]
794    pub fn replace_zone(&mut self, idx: u32, zone: SDPZone) -> Result<(), glib::BoolError> {
795        if idx >= self.zones_len() {
796            return Err(glib::bool_error!("Failed to replace zone"));
797        }
798
799        let mut zone = mem::ManuallyDrop::new(zone);
800        let result = unsafe { ffi::gst_sdp_message_replace_zone(&mut self.0, idx, &mut zone.0) };
801        match result {
802            ffi::GST_SDP_OK => Ok(()),
803            _ => Err(glib::bool_error!("Failed to replace zone")),
804        }
805    }
806
807    #[doc(alias = "gst_sdp_message_set_connection")]
808    pub fn set_connection(
809        &mut self,
810        nettype: &str,
811        addrtype: &str,
812        address: &str,
813        ttl: u32,
814        addr_number: u32,
815    ) {
816        unsafe {
817            ffi::gst_sdp_message_set_connection(
818                &mut self.0,
819                nettype.to_glib_none().0,
820                addrtype.to_glib_none().0,
821                address.to_glib_none().0,
822                ttl,
823                addr_number,
824            )
825        };
826    }
827
828    #[doc(alias = "gst_sdp_message_set_information")]
829    pub fn set_information(&mut self, information: &str) {
830        unsafe { ffi::gst_sdp_message_set_information(&mut self.0, information.to_glib_none().0) };
831    }
832
833    #[doc(alias = "gst_sdp_message_set_key")]
834    pub fn set_key(&mut self, type_: &str, data: &str) {
835        unsafe {
836            ffi::gst_sdp_message_set_key(&mut self.0, type_.to_glib_none().0, data.to_glib_none().0)
837        };
838    }
839
840    #[doc(alias = "gst_sdp_message_set_origin")]
841    pub fn set_origin(
842        &mut self,
843        username: &str,
844        sess_id: &str,
845        sess_version: &str,
846        nettype: &str,
847        addrtype: &str,
848        addr: &str,
849    ) {
850        unsafe {
851            ffi::gst_sdp_message_set_origin(
852                &mut self.0,
853                username.to_glib_none().0,
854                sess_id.to_glib_none().0,
855                sess_version.to_glib_none().0,
856                nettype.to_glib_none().0,
857                addrtype.to_glib_none().0,
858                addr.to_glib_none().0,
859            )
860        };
861    }
862
863    #[doc(alias = "gst_sdp_message_set_session_name")]
864    pub fn set_session_name(&mut self, session_name: &str) {
865        unsafe {
866            ffi::gst_sdp_message_set_session_name(&mut self.0, session_name.to_glib_none().0)
867        };
868    }
869
870    #[doc(alias = "gst_sdp_message_set_uri")]
871    pub fn set_uri(&mut self, uri: &str) {
872        unsafe { ffi::gst_sdp_message_set_uri(&mut self.0, uri.to_glib_none().0) };
873    }
874
875    #[doc(alias = "gst_sdp_message_set_version")]
876    pub fn set_version(&mut self, version: &str) {
877        unsafe { ffi::gst_sdp_message_set_version(&mut self.0, version.to_glib_none().0) };
878    }
879
880    #[doc(alias = "gst_sdp_message_times_len")]
881    pub fn times_len(&self) -> u32 {
882        unsafe { ffi::gst_sdp_message_times_len(&self.0) }
883    }
884
885    #[doc(alias = "gst_sdp_message_zones_len")]
886    pub fn zones_len(&self) -> u32 {
887        unsafe { ffi::gst_sdp_message_zones_len(&self.0) }
888    }
889
890    #[doc(alias = "gst_sdp_message_as_uri")]
891    pub fn as_uri(&self, scheme: &str) -> Result<String, glib::error::BoolError> {
892        skip_assert_initialized!();
893        unsafe {
894            match from_glib_full(ffi::gst_sdp_message_as_uri(
895                scheme.to_glib_none().0,
896                &self.0,
897            )) {
898                Some(s) => Ok(s),
899                None => Err(glib::bool_error!("Failed to create an URI from message")),
900            }
901        }
902    }
903
904    pub fn attributes(&self) -> AttributesIter {
905        AttributesIter::new(self)
906    }
907
908    pub fn bandwidths(&self) -> BandwidthsIter {
909        BandwidthsIter::new(self)
910    }
911
912    pub fn emails(&self) -> EmailsIter {
913        EmailsIter::new(self)
914    }
915
916    pub fn medias(&self) -> MediasIter {
917        MediasIter::new(self)
918    }
919
920    pub fn medias_mut(&mut self) -> MediasIterMut {
921        MediasIterMut::new(self)
922    }
923
924    pub fn phones(&self) -> PhonesIter {
925        PhonesIter::new(self)
926    }
927
928    pub fn times(&self) -> TimesIter {
929        TimesIter::new(self)
930    }
931
932    pub fn zones(&self) -> ZonesIter {
933        ZonesIter::new(self)
934    }
935}
936
937impl Borrow<SDPMessageRef> for SDPMessage {
938    fn borrow(&self) -> &SDPMessageRef {
939        self
940    }
941}
942
943impl BorrowMut<SDPMessageRef> for SDPMessage {
944    fn borrow_mut(&mut self) -> &mut SDPMessageRef {
945        &mut *self
946    }
947}
948
949impl ToOwned for SDPMessageRef {
950    type Owned = SDPMessage;
951
952    fn to_owned(&self) -> SDPMessage {
953        unsafe {
954            let mut ptr = ptr::null_mut();
955            ffi::gst_sdp_message_copy(&self.0, &mut ptr);
956            from_glib_full(ptr)
957        }
958    }
959}
960
961impl glib::types::StaticType for SDPMessageRef {
962    fn static_type() -> glib::types::Type {
963        unsafe { from_glib(ffi::gst_sdp_message_get_type()) }
964    }
965}
966
967unsafe impl<'a> glib::value::FromValue<'a> for &'a SDPMessageRef {
968    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
969
970    unsafe fn from_value(value: &'a glib::Value) -> Self {
971        skip_assert_initialized!();
972        &*(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut SDPMessageRef)
973    }
974}
975
976impl glib::value::ToValue for SDPMessageRef {
977    fn to_value(&self) -> glib::Value {
978        let mut value = glib::Value::for_value_type::<SDPMessage>();
979        unsafe {
980            glib::gobject_ffi::g_value_set_boxed(
981                value.to_glib_none_mut().0,
982                &self.0 as *const ffi::GstSDPMessage as *mut _,
983            )
984        }
985        value
986    }
987
988    fn value_type(&self) -> glib::Type {
989        Self::static_type()
990    }
991}
992
993impl glib::value::ToValueOptional for SDPMessageRef {
994    fn to_value_optional(s: Option<&Self>) -> glib::Value {
995        skip_assert_initialized!();
996        let mut value = glib::Value::for_value_type::<SDPMessage>();
997        unsafe {
998            glib::gobject_ffi::g_value_set_boxed(
999                value.to_glib_none_mut().0,
1000                s.map(|s| &s.0 as *const ffi::GstSDPMessage)
1001                    .unwrap_or(ptr::null()) as *mut _,
1002            )
1003        }
1004        value
1005    }
1006}
1007
1008macro_rules! define_iter(
1009    ($name:ident, $typ:ty, $get_item:expr, $get_len:expr) => {
1010    #[must_use = "iterators are lazy and do nothing unless consumed"]
1011    #[derive(Debug)]
1012    pub struct $name<'a> {
1013        message: &'a SDPMessageRef,
1014        idx: usize,
1015        len: usize,
1016    }
1017
1018    #[allow(clippy::redundant_closure_call)]
1019    impl<'a> $name<'a> {
1020        fn new(message: &'a SDPMessageRef) -> $name<'a> {
1021            skip_assert_initialized!();
1022            let len = $get_len(message);
1023
1024            $name {
1025                message,
1026                idx: 0,
1027                len: len as usize,
1028            }
1029        }
1030    }
1031
1032    #[allow(clippy::redundant_closure_call)]
1033    impl<'a> Iterator for $name<'a> {
1034        type Item = $typ;
1035
1036        fn next(&mut self) -> Option<Self::Item> {
1037            if self.idx >= self.len {
1038                return None;
1039            }
1040
1041            let item = $get_item(self.message, self.idx as u32).unwrap();
1042            self.idx += 1;
1043            Some(item)
1044        }
1045
1046        fn size_hint(&self) -> (usize, Option<usize>) {
1047            let remaining = self.len - self.idx;
1048
1049            (remaining, Some(remaining))
1050        }
1051
1052        fn count(self) -> usize {
1053            self.len - self.idx
1054        }
1055
1056        fn nth(&mut self, n: usize) -> Option<Self::Item> {
1057            let (end, overflow) = self.idx.overflowing_add(n);
1058            if end >= self.len || overflow {
1059                self.idx = self.len;
1060                None
1061            } else {
1062                self.idx = end + 1;
1063                Some($get_item(self.message, end as u32).unwrap())
1064            }
1065        }
1066
1067        fn last(self) -> Option<Self::Item> {
1068            if self.idx == self.len {
1069                None
1070            } else {
1071                Some($get_item(self.message, self.len as u32 - 1).unwrap())
1072            }
1073        }
1074    }
1075
1076    #[allow(clippy::redundant_closure_call)]
1077    impl<'a> DoubleEndedIterator for $name<'a> {
1078        fn next_back(&mut self) -> Option<Self::Item> {
1079            if self.idx == self.len {
1080                return None;
1081            }
1082
1083            self.len -= 1;
1084
1085            Some($get_item(self.message, self.len as u32).unwrap())
1086        }
1087
1088        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1089            let (end, overflow) = self.len.overflowing_sub(n);
1090            if end <= self.idx || overflow {
1091                self.idx = self.len;
1092                None
1093            } else {
1094                self.len = end - 1;
1095                Some($get_item(self.message, self.len as u32).unwrap())
1096            }
1097        }
1098    }
1099
1100    impl<'a> ExactSizeIterator for $name<'a> {}
1101    impl<'a> std::iter::FusedIterator for $name<'a> {}
1102    }
1103);
1104
1105macro_rules! define_iter_mut(
1106    ($name:ident, $typ:ty, $get_item:expr, $get_len:expr) => {
1107    #[must_use = "iterators are lazy and do nothing unless consumed"]
1108    #[derive(Debug)]
1109    pub struct $name<'a> {
1110        message: &'a mut SDPMessageRef,
1111        idx: usize,
1112        len: usize,
1113    }
1114
1115    #[allow(clippy::redundant_closure_call)]
1116    impl<'a> $name<'a> {
1117        fn new(message: &'a mut SDPMessageRef) -> $name<'a> {
1118            skip_assert_initialized!();
1119            let len = $get_len(message);
1120
1121            $name {
1122                message,
1123                idx: 0,
1124                len: len as usize,
1125            }
1126        }
1127    }
1128
1129    #[allow(clippy::redundant_closure_call)]
1130    impl<'a> Iterator for $name<'a> {
1131        type Item = $typ;
1132
1133        fn next(&mut self) -> Option<Self::Item> {
1134            // The lifetime of the passed self is not 'a but we need to return a message reference
1135            // with that lifetime here. The reason here is that the compiler does not and can't
1136            // know that it's statically impossible to mutate the message between different calls
1137            // to next(), so it has to assume that every call to next() will invalidate any
1138            // returned references.
1139            //
1140            // In theory we could have a function on the iterator that mutates the message and for
1141            // example removes the message that was returned here at an earlier time. The compiler
1142            // would be correct to complain in that case, but we don't provide such a function.
1143            let message = unsafe {
1144                &mut *(self.message as *mut SDPMessageRef)
1145            };
1146            if self.idx >= self.len {
1147                return None;
1148            }
1149
1150            let item = $get_item(message, self.idx as u32).unwrap();
1151            self.idx += 1;
1152            Some(item)
1153        }
1154
1155        fn size_hint(&self) -> (usize, Option<usize>) {
1156            let remaining = self.len - self.idx;
1157
1158            (remaining, Some(remaining))
1159        }
1160
1161
1162        fn count(self) -> usize {
1163            self.len - self.idx
1164        }
1165
1166        fn nth(&mut self, n: usize) -> Option<Self::Item> {
1167            let message = unsafe {
1168                &mut *(self.message as *mut SDPMessageRef)
1169            };
1170            let (end, overflow) = self.idx.overflowing_add(n);
1171            if end >= self.len || overflow {
1172                self.idx = self.len;
1173                None
1174            } else {
1175                self.idx = end + 1;
1176                Some($get_item(message, end as u32).unwrap())
1177            }
1178        }
1179
1180        fn last(self) -> Option<Self::Item> {
1181            if self.idx == self.len {
1182                None
1183            } else {
1184                Some($get_item(self.message, self.len as u32 - 1).unwrap())
1185            }
1186        }
1187    }
1188
1189    #[allow(clippy::redundant_closure_call)]
1190    impl<'a> DoubleEndedIterator for $name<'a> {
1191        fn next_back(&mut self) -> Option<Self::Item> {
1192            let message = unsafe {
1193                &mut *(self.message as *mut SDPMessageRef)
1194            };
1195            if self.idx == self.len {
1196                return None;
1197            }
1198
1199            self.len -= 1;
1200            Some($get_item(message, self.len as u32).unwrap())
1201        }
1202
1203
1204        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1205            let message = unsafe {
1206                &mut *(self.message as *mut SDPMessageRef)
1207            };
1208            let (end, overflow) = self.len.overflowing_sub(n);
1209            if end <= self.idx || overflow {
1210                self.idx = self.len;
1211                None
1212            } else {
1213                self.len = end - 1;
1214                Some($get_item(message, self.len as u32).unwrap())
1215            }
1216        }
1217    }
1218
1219    impl<'a> ExactSizeIterator for $name<'a> {}
1220    impl<'a> std::iter::FusedIterator for $name<'a> {}
1221    }
1222);
1223
1224define_iter!(
1225    AttributesIter,
1226    &'a SDPAttribute,
1227    |message: &'a SDPMessageRef, idx| message.attribute(idx),
1228    |message: &SDPMessageRef| message.attributes_len()
1229);
1230define_iter!(
1231    BandwidthsIter,
1232    &'a SDPBandwidth,
1233    |message: &'a SDPMessageRef, idx| message.bandwidth(idx),
1234    |message: &SDPMessageRef| message.bandwidths_len()
1235);
1236define_iter!(
1237    EmailsIter,
1238    &'a str,
1239    |message: &'a SDPMessageRef, idx| message.email(idx),
1240    |message: &SDPMessageRef| message.emails_len()
1241);
1242define_iter!(
1243    MediasIter,
1244    &'a SDPMediaRef,
1245    |message: &'a SDPMessageRef, idx| message.media(idx),
1246    |message: &SDPMessageRef| message.medias_len()
1247);
1248define_iter_mut!(
1249    MediasIterMut,
1250    &'a mut SDPMediaRef,
1251    |message: &'a mut SDPMessageRef, idx| message.media_mut(idx),
1252    |message: &SDPMessageRef| message.medias_len()
1253);
1254define_iter!(
1255    PhonesIter,
1256    &'a str,
1257    |message: &'a SDPMessageRef, idx| message.phone(idx),
1258    |message: &SDPMessageRef| message.phones_len()
1259);
1260define_iter!(
1261    TimesIter,
1262    &'a SDPTime,
1263    |message: &'a SDPMessageRef, idx| message.time(idx),
1264    |message: &SDPMessageRef| message.times_len()
1265);
1266define_iter!(
1267    ZonesIter,
1268    &'a SDPZone,
1269    |message: &'a SDPMessageRef, idx| message.zone(idx),
1270    |message: &SDPMessageRef| message.zones_len()
1271);
1272
1273#[cfg(test)]
1274mod tests {
1275    use crate::SDPMessage;
1276
1277    fn init() {
1278        gst::init().unwrap();
1279    }
1280
1281    #[test]
1282    fn media_from_message() {
1283        init();
1284
1285        let sdp = "v=0\r\no=- 1938737043334325940 0 IN IP4 0.0.0.0\r\ns=-\r\nt=0 0\r\na=ice-options:trickle\r\nm=video 9 UDP/TLS/RTP/SAVPF 96\r\nc=IN IP4 0.0.0.0\r\na=setup:actpass\r\na=ice-ufrag:YZxU9JlWHzHcF6O2U09/q3PvBhbTPdZW\r\na=ice-pwd:fyrt730GWo5mFGc9m2z/vbUu3z1lewla\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:96 VP8/90000\r\na=rtcp-fb:96 nack\r\na=rtcp-fb:96 nack pli\r\na=framerate:30\r\na=mid:video0\r\na=fingerprint:sha-256 DB:48:8F:18:13:F3:AA:13:31:B3:75:3D:1A:D3:BA:88:4A:ED:1B:56:14:C3:09:CD:BC:4D:18:42:B9:6A:5F:98\r\nm=audio 9 UDP/TLS/RTP/SAVPF 97\r\nc=IN IP4 0.0.0.0\r\na=setup:actpass\r\na=ice-ufrag:04KZM9qE2S4r06AN6A9CeXOM6mzO0LZY\r\na=ice-pwd:cJTSfHF6hHDAcsTJXZVJeuYCC6rKqBvW\r\na=sendrecv\r\na=rtcp-mux\r\na=rtcp-rsize\r\na=rtpmap:97 OPUS/48000/2\r\na=rtcp-fb:97 nack\r\na=rtcp-fb:97 nack pli\r\na=mid:audio1\r\na=fingerprint:sha-256 DB:48:8F:18:13:F3:AA:13:31:B3:75:3D:1A:D3:BA:88:4A:ED:1B:56:14:C3:09:CD:BC:4D:18:42:B9:6A:5F:98\r\n";
1286        let sdp = SDPMessage::parse_buffer(sdp.as_bytes()).unwrap();
1287        let media = sdp.media(0).unwrap();
1288        assert_eq!(media.formats_len(), 1);
1289    }
1290
1291    #[test]
1292    fn debug_impl() {
1293        init();
1294
1295        let sdp = SDPMessage::new();
1296        assert!(!format!("{sdp:?}").is_empty());
1297    }
1298}