Skip to main content

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