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    #[derive(Debug)]
1011    pub struct $name<'a> {
1012        message: &'a SDPMessageRef,
1013        idx: usize,
1014        len: usize,
1015    }
1016
1017    #[allow(clippy::redundant_closure_call)]
1018    impl<'a> $name<'a> {
1019        fn new(message: &'a SDPMessageRef) -> $name<'a> {
1020            skip_assert_initialized!();
1021            let len = $get_len(message);
1022
1023            $name {
1024                message,
1025                idx: 0,
1026                len: len as usize,
1027            }
1028        }
1029    }
1030
1031    #[allow(clippy::redundant_closure_call)]
1032    impl<'a> Iterator for $name<'a> {
1033        type Item = $typ;
1034
1035        fn next(&mut self) -> Option<Self::Item> {
1036            if self.idx >= self.len {
1037                return None;
1038            }
1039
1040            let item = $get_item(self.message, self.idx as u32).unwrap();
1041            self.idx += 1;
1042            Some(item)
1043        }
1044
1045        fn size_hint(&self) -> (usize, Option<usize>) {
1046            let remaining = self.len - self.idx;
1047
1048            (remaining, Some(remaining))
1049        }
1050
1051        fn count(self) -> usize {
1052            self.len - self.idx
1053        }
1054
1055        fn nth(&mut self, n: usize) -> Option<Self::Item> {
1056            let (end, overflow) = self.idx.overflowing_add(n);
1057            if end >= self.len || overflow {
1058                self.idx = self.len;
1059                None
1060            } else {
1061                self.idx = end + 1;
1062                Some($get_item(self.message, end as u32).unwrap())
1063            }
1064        }
1065
1066        fn last(self) -> Option<Self::Item> {
1067            if self.idx == self.len {
1068                None
1069            } else {
1070                Some($get_item(self.message, self.len as u32 - 1).unwrap())
1071            }
1072        }
1073    }
1074
1075    #[allow(clippy::redundant_closure_call)]
1076    impl<'a> DoubleEndedIterator for $name<'a> {
1077        fn next_back(&mut self) -> Option<Self::Item> {
1078            if self.idx == self.len {
1079                return None;
1080            }
1081
1082            self.len -= 1;
1083
1084            Some($get_item(self.message, self.len as u32).unwrap())
1085        }
1086
1087        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1088            let (end, overflow) = self.len.overflowing_sub(n);
1089            if end <= self.idx || overflow {
1090                self.idx = self.len;
1091                None
1092            } else {
1093                self.len = end - 1;
1094                Some($get_item(self.message, self.len as u32).unwrap())
1095            }
1096        }
1097    }
1098
1099    impl<'a> ExactSizeIterator for $name<'a> {}
1100    impl<'a> std::iter::FusedIterator for $name<'a> {}
1101    }
1102);
1103
1104macro_rules! define_iter_mut(
1105    ($name:ident, $typ:ty, $get_item:expr, $get_len:expr) => {
1106    #[derive(Debug)]
1107    pub struct $name<'a> {
1108        message: &'a mut SDPMessageRef,
1109        idx: usize,
1110        len: usize,
1111    }
1112
1113    #[allow(clippy::redundant_closure_call)]
1114    impl<'a> $name<'a> {
1115        fn new(message: &'a mut SDPMessageRef) -> $name<'a> {
1116            skip_assert_initialized!();
1117            let len = $get_len(message);
1118
1119            $name {
1120                message,
1121                idx: 0,
1122                len: len as usize,
1123            }
1124        }
1125    }
1126
1127    #[allow(clippy::redundant_closure_call)]
1128    impl<'a> Iterator for $name<'a> {
1129        type Item = $typ;
1130
1131        fn next(&mut self) -> Option<Self::Item> {
1132            // The lifetime of the passed self is not 'a but we need to return a message reference
1133            // with that lifetime here. The reason here is that the compiler does not and can't
1134            // know that it's statically impossible to mutate the message between different calls
1135            // to next(), so it has to assume that every call to next() will invalidate any
1136            // returned references.
1137            //
1138            // In theory we could have a function on the iterator that mutates the message and for
1139            // example removes the message that was returned here at an earlier time. The compiler
1140            // would be correct to complain in that case, but we don't provide such a function.
1141            let message = unsafe {
1142                &mut *(self.message as *mut SDPMessageRef)
1143            };
1144            if self.idx >= self.len {
1145                return None;
1146            }
1147
1148            let item = $get_item(message, self.idx as u32).unwrap();
1149            self.idx += 1;
1150            Some(item)
1151        }
1152
1153        fn size_hint(&self) -> (usize, Option<usize>) {
1154            let remaining = self.len - self.idx;
1155
1156            (remaining, Some(remaining))
1157        }
1158
1159
1160        fn count(self) -> usize {
1161            self.len - self.idx
1162        }
1163
1164        fn nth(&mut self, n: usize) -> Option<Self::Item> {
1165            let message = unsafe {
1166                &mut *(self.message as *mut SDPMessageRef)
1167            };
1168            let (end, overflow) = self.idx.overflowing_add(n);
1169            if end >= self.len || overflow {
1170                self.idx = self.len;
1171                None
1172            } else {
1173                self.idx = end + 1;
1174                Some($get_item(message, end as u32).unwrap())
1175            }
1176        }
1177
1178        fn last(self) -> Option<Self::Item> {
1179            if self.idx == self.len {
1180                None
1181            } else {
1182                Some($get_item(self.message, self.len as u32 - 1).unwrap())
1183            }
1184        }
1185    }
1186
1187    #[allow(clippy::redundant_closure_call)]
1188    impl<'a> DoubleEndedIterator for $name<'a> {
1189        fn next_back(&mut self) -> Option<Self::Item> {
1190            let message = unsafe {
1191                &mut *(self.message as *mut SDPMessageRef)
1192            };
1193            if self.idx == self.len {
1194                return None;
1195            }
1196
1197            self.len -= 1;
1198            Some($get_item(message, self.len as u32).unwrap())
1199        }
1200
1201
1202        fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1203            let message = unsafe {
1204                &mut *(self.message as *mut SDPMessageRef)
1205            };
1206            let (end, overflow) = self.len.overflowing_sub(n);
1207            if end <= self.idx || overflow {
1208                self.idx = self.len;
1209                None
1210            } else {
1211                self.len = end - 1;
1212                Some($get_item(message, self.len as u32).unwrap())
1213            }
1214        }
1215    }
1216
1217    impl<'a> ExactSizeIterator for $name<'a> {}
1218    impl<'a> std::iter::FusedIterator for $name<'a> {}
1219    }
1220);
1221
1222define_iter!(
1223    AttributesIter,
1224    &'a SDPAttribute,
1225    |message: &'a SDPMessageRef, idx| message.attribute(idx),
1226    |message: &SDPMessageRef| message.attributes_len()
1227);
1228define_iter!(
1229    BandwidthsIter,
1230    &'a SDPBandwidth,
1231    |message: &'a SDPMessageRef, idx| message.bandwidth(idx),
1232    |message: &SDPMessageRef| message.bandwidths_len()
1233);
1234define_iter!(
1235    EmailsIter,
1236    &'a str,
1237    |message: &'a SDPMessageRef, idx| message.email(idx),
1238    |message: &SDPMessageRef| message.emails_len()
1239);
1240define_iter!(
1241    MediasIter,
1242    &'a SDPMediaRef,
1243    |message: &'a SDPMessageRef, idx| message.media(idx),
1244    |message: &SDPMessageRef| message.medias_len()
1245);
1246define_iter_mut!(
1247    MediasIterMut,
1248    &'a mut SDPMediaRef,
1249    |message: &'a mut SDPMessageRef, idx| message.media_mut(idx),
1250    |message: &SDPMessageRef| message.medias_len()
1251);
1252define_iter!(
1253    PhonesIter,
1254    &'a str,
1255    |message: &'a SDPMessageRef, idx| message.phone(idx),
1256    |message: &SDPMessageRef| message.phones_len()
1257);
1258define_iter!(
1259    TimesIter,
1260    &'a SDPTime,
1261    |message: &'a SDPMessageRef, idx| message.time(idx),
1262    |message: &SDPMessageRef| message.times_len()
1263);
1264define_iter!(
1265    ZonesIter,
1266    &'a SDPZone,
1267    |message: &'a SDPMessageRef, idx| message.zone(idx),
1268    |message: &SDPMessageRef| message.zones_len()
1269);
1270
1271#[cfg(test)]
1272mod tests {
1273    use crate::SDPMessage;
1274
1275    fn init() {
1276        gst::init().unwrap();
1277    }
1278
1279    #[test]
1280    fn media_from_message() {
1281        init();
1282
1283        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";
1284        let sdp = SDPMessage::parse_buffer(sdp.as_bytes()).unwrap();
1285        let media = sdp.media(0).unwrap();
1286        assert_eq!(media.formats_len(), 1);
1287    }
1288
1289    #[test]
1290    fn debug_impl() {
1291        init();
1292
1293        let sdp = SDPMessage::new();
1294        assert!(!format!("{sdp:?}").is_empty());
1295    }
1296}