gstreamer_rtp/
rtp_buffer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem, ptr, slice};
4
5use crate::ffi;
6use glib::translate::{from_glib, mut_override, FromGlibPtrFull, IntoGlib};
7
8pub enum Readable {}
9pub enum Writable {}
10
11/// The GstRTPBuffer helper functions makes it easy to parse and create regular
12/// [`gst::Buffer`][crate::gst::Buffer] objects that contain RTP payloads. These buffers are typically of
13/// 'application/x-rtp' [`gst::Caps`][crate::gst::Caps].
14pub struct RTPBuffer<'a, T> {
15    rtp_buffer: ffi::GstRTPBuffer,
16    phantom: PhantomData<&'a T>,
17}
18
19unsafe impl<T> Send for RTPBuffer<'_, T> {}
20unsafe impl<T> Sync for RTPBuffer<'_, T> {}
21
22impl<T> fmt::Debug for RTPBuffer<'_, T> {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        f.debug_struct("RTPBuffer")
25            .field("rtp_buffer", &self.rtp_buffer)
26            .finish()
27    }
28}
29
30impl<'a> RTPBuffer<'a, Readable> {
31    #[inline]
32    pub fn from_buffer_readable(
33        buffer: &'a gst::BufferRef,
34    ) -> Result<RTPBuffer<'a, Readable>, glib::BoolError> {
35        skip_assert_initialized!();
36        unsafe {
37            let mut rtp_buffer = mem::MaybeUninit::zeroed();
38            let res: bool = from_glib(ffi::gst_rtp_buffer_map(
39                mut_override(buffer.as_ptr()),
40                gst::ffi::GST_MAP_READ,
41                rtp_buffer.as_mut_ptr(),
42            ));
43
44            if res {
45                Ok(RTPBuffer {
46                    rtp_buffer: rtp_buffer.assume_init(),
47                    phantom: PhantomData,
48                })
49            } else {
50                Err(glib::bool_error!("Failed to map RTP buffer readable"))
51            }
52        }
53    }
54
55    #[inline]
56    pub unsafe fn from_glib_borrow<'b>(
57        rtp_buffer: *mut ffi::GstRTPBuffer,
58    ) -> glib::translate::Borrowed<RTPBuffer<'b, Readable>> {
59        glib::translate::Borrowed::new(RTPBuffer {
60            rtp_buffer: *rtp_buffer,
61            phantom: PhantomData,
62        })
63    }
64}
65
66impl<'a> RTPBuffer<'a, Writable> {
67    #[inline]
68    pub fn from_buffer_writable(
69        buffer: &'a mut gst::BufferRef,
70    ) -> Result<RTPBuffer<'a, Writable>, glib::BoolError> {
71        skip_assert_initialized!();
72        unsafe {
73            let mut rtp_buffer = mem::MaybeUninit::zeroed();
74            let res: bool = from_glib(ffi::gst_rtp_buffer_map(
75                buffer.as_mut_ptr(),
76                gst::ffi::GST_MAP_READWRITE,
77                rtp_buffer.as_mut_ptr(),
78            ));
79
80            if res {
81                Ok(RTPBuffer {
82                    rtp_buffer: rtp_buffer.assume_init(),
83                    phantom: PhantomData,
84                })
85            } else {
86                Err(glib::bool_error!("Failed to map RTP buffer writable"))
87            }
88        }
89    }
90
91    #[doc(alias = "gst_rtp_buffer_set_seq")]
92    pub fn set_seq(&mut self, seq: u16) {
93        unsafe {
94            ffi::gst_rtp_buffer_set_seq(&mut self.rtp_buffer, seq);
95        }
96    }
97
98    #[doc(alias = "gst_rtp_buffer_set_marker")]
99    pub fn set_marker(&mut self, m: bool) {
100        unsafe {
101            ffi::gst_rtp_buffer_set_marker(&mut self.rtp_buffer, m.into_glib());
102        }
103    }
104
105    #[doc(alias = "gst_rtp_buffer_set_payload_type")]
106    pub fn set_payload_type(&mut self, pt: u8) {
107        unsafe {
108            ffi::gst_rtp_buffer_set_payload_type(&mut self.rtp_buffer, pt);
109        }
110    }
111
112    #[doc(alias = "gst_rtp_buffer_set_ssrc")]
113    pub fn set_ssrc(&mut self, ssrc: u32) {
114        unsafe { ffi::gst_rtp_buffer_set_ssrc(&mut self.rtp_buffer, ssrc) }
115    }
116
117    #[doc(alias = "gst_rtp_buffer_set_csrc")]
118    pub fn set_csrc(&mut self, idx: u8, ssrc: u32) {
119        unsafe { ffi::gst_rtp_buffer_set_csrc(&mut self.rtp_buffer, idx, ssrc) }
120    }
121
122    #[doc(alias = "gst_rtp_buffer_set_timestamp")]
123    pub fn set_timestamp(&mut self, rtptime: u32) {
124        unsafe {
125            ffi::gst_rtp_buffer_set_timestamp(&mut self.rtp_buffer, rtptime);
126        }
127    }
128
129    #[doc(alias = "gst_rtp_buffer_set_extension")]
130    pub fn set_extension(&mut self, extension: bool) {
131        unsafe { ffi::gst_rtp_buffer_set_extension(&mut self.rtp_buffer, extension.into_glib()) }
132    }
133
134    #[doc(alias = "gst_rtp_buffer_add_extension_onebyte_header")]
135    #[allow(clippy::manual_range_contains)]
136    pub fn add_extension_onebyte_header(
137        &mut self,
138        id: u8,
139        data: &[u8],
140    ) -> Result<(), glib::BoolError> {
141        assert!(
142            id >= 1 && id <= 14,
143            "id should be between 1 and 14 (inclusive)"
144        );
145        assert!(
146            !data.is_empty() && data.len() <= 16,
147            "data size should be between 1 and 16 (inclusive"
148        );
149        unsafe {
150            let result: bool = from_glib(ffi::gst_rtp_buffer_add_extension_onebyte_header(
151                &mut self.rtp_buffer,
152                id,
153                data.as_ptr() as glib::ffi::gconstpointer,
154                data.len() as u32,
155            ));
156            if result {
157                Ok(())
158            } else {
159                Err(glib::bool_error!("Failed to add onebyte header extension"))
160            }
161        }
162    }
163
164    #[doc(alias = "gst_rtp_buffer_add_extension_twobytes_header")]
165    pub fn add_extension_twobytes_header(
166        &mut self,
167        appbits: u8,
168        id: u8,
169        data: &[u8],
170    ) -> Result<(), glib::BoolError> {
171        assert_eq!(
172            appbits & 0xF0,
173            0,
174            "appbits must use only 4 bits (max value is 15)"
175        );
176        assert!(data.len() < 256, "data size should be smaller than 256");
177        unsafe {
178            let result: bool = from_glib(ffi::gst_rtp_buffer_add_extension_twobytes_header(
179                &mut self.rtp_buffer,
180                appbits,
181                id,
182                data.as_ptr() as glib::ffi::gconstpointer,
183                data.len() as u32,
184            ));
185            if result {
186                Ok(())
187            } else {
188                Err(glib::bool_error!("Failed to add twobytes header extension"))
189            }
190        }
191    }
192
193    #[cfg(feature = "v1_20")]
194    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
195    #[doc(alias = "gst_rtp_buffer_remove_extension_data")]
196    pub fn remove_extension_data(&mut self) {
197        unsafe {
198            ffi::gst_rtp_buffer_remove_extension_data(&mut self.rtp_buffer);
199        }
200    }
201
202    #[doc(alias = "gst_rtp_buffer_set_padding")]
203    pub fn set_padding(&mut self, padding: bool) {
204        unsafe { ffi::gst_rtp_buffer_set_padding(&mut self.rtp_buffer, padding.into_glib()) }
205    }
206}
207
208impl<T> RTPBuffer<'_, T> {
209    #[doc(alias = "get_seq")]
210    #[doc(alias = "gst_rtp_buffer_get_seq")]
211    pub fn seq(&self) -> u16 {
212        unsafe { ffi::gst_rtp_buffer_get_seq(glib::translate::mut_override(&self.rtp_buffer)) }
213    }
214
215    #[doc(alias = "get_payload_type")]
216    #[doc(alias = "gst_rtp_buffer_get_payload_type")]
217    pub fn payload_type(&self) -> u8 {
218        unsafe {
219            ffi::gst_rtp_buffer_get_payload_type(glib::translate::mut_override(&self.rtp_buffer))
220        }
221    }
222
223    #[doc(alias = "get_ssrc")]
224    #[doc(alias = "gst_rtp_buffer_get_ssrc")]
225    pub fn ssrc(&self) -> u32 {
226        unsafe { ffi::gst_rtp_buffer_get_ssrc(glib::translate::mut_override(&self.rtp_buffer)) }
227    }
228
229    #[doc(alias = "get_timestamp")]
230    #[doc(alias = "gst_rtp_buffer_get_timestamp")]
231    pub fn timestamp(&self) -> u32 {
232        unsafe {
233            ffi::gst_rtp_buffer_get_timestamp(glib::translate::mut_override(&self.rtp_buffer))
234        }
235    }
236
237    #[doc(alias = "get_csrc")]
238    #[doc(alias = "gst_rtp_buffer_get_csrc")]
239    pub fn csrc(&self, idx: u8) -> Option<u32> {
240        if idx < self.csrc_count() {
241            unsafe {
242                Some(ffi::gst_rtp_buffer_get_csrc(
243                    glib::translate::mut_override(&self.rtp_buffer),
244                    idx,
245                ))
246            }
247        } else {
248            None
249        }
250    }
251
252    #[doc(alias = "get_csrc_count")]
253    #[doc(alias = "gst_rtp_buffer_get_csrc_count")]
254    pub fn csrc_count(&self) -> u8 {
255        unsafe {
256            ffi::gst_rtp_buffer_get_csrc_count(glib::translate::mut_override(&self.rtp_buffer))
257        }
258    }
259
260    #[doc(alias = "get_marker")]
261    pub fn is_marker(&self) -> bool {
262        unsafe {
263            from_glib(ffi::gst_rtp_buffer_get_marker(
264                glib::translate::mut_override(&self.rtp_buffer),
265            ))
266        }
267    }
268
269    #[doc(alias = "get_payload_size")]
270    pub fn payload_size(&self) -> u32 {
271        unsafe {
272            ffi::gst_rtp_buffer_get_payload_len(glib::translate::mut_override(&self.rtp_buffer))
273        }
274    }
275
276    #[doc(alias = "get_payload")]
277    #[doc(alias = "gst_rtp_buffer_get_payload")]
278    pub fn payload(&self) -> Result<&[u8], glib::error::BoolError> {
279        let size = self.payload_size();
280        if size == 0 {
281            return Ok(&[]);
282        }
283        unsafe {
284            let pointer =
285                ffi::gst_rtp_buffer_get_payload(glib::translate::mut_override(&self.rtp_buffer));
286            if pointer.is_null() {
287                Err(glib::bool_error!("Failed to get payload data"))
288            } else {
289                Ok(slice::from_raw_parts(pointer as *const u8, size as usize))
290            }
291        }
292    }
293
294    #[doc(alias = "get_payload")]
295    #[doc(alias = "gst_rtp_buffer_get_payload")]
296    pub fn payload_mut(&mut self) -> Result<&mut [u8], glib::error::BoolError> {
297        let size = self.payload_size();
298        if size == 0 {
299            return Ok(&mut []);
300        }
301        unsafe {
302            let pointer = ffi::gst_rtp_buffer_get_payload(&mut self.rtp_buffer);
303            if pointer.is_null() {
304                Err(glib::bool_error!("Failed to get payload data"))
305            } else {
306                Ok(slice::from_raw_parts_mut(pointer as *mut u8, size as usize))
307            }
308        }
309    }
310
311    #[doc(alias = "get_payload_buffer")]
312    #[doc(alias = "gst_rtp_buffer_get_payload_buffer")]
313    pub fn payload_buffer(&self) -> Result<gst::Buffer, glib::BoolError> {
314        unsafe {
315            Option::<_>::from_glib_full(ffi::gst_rtp_buffer_get_payload_buffer(
316                glib::translate::mut_override(&self.rtp_buffer),
317            ))
318            .ok_or_else(|| glib::bool_error!("Failed to get payload buffer"))
319        }
320    }
321
322    #[inline]
323    pub fn buffer(&self) -> &gst::BufferRef {
324        unsafe {
325            let ptr = self.rtp_buffer.buffer;
326
327            debug_assert!(!ptr.is_null());
328
329            gst::BufferRef::from_ptr(ptr)
330        }
331    }
332
333    #[doc(alias = "get_extension")]
334    pub fn is_extension(&self) -> bool {
335        unsafe {
336            from_glib(ffi::gst_rtp_buffer_get_extension(
337                glib::translate::mut_override(&self.rtp_buffer),
338            ))
339        }
340    }
341
342    #[doc(alias = "get_extension_bytes")]
343    #[doc(alias = "gst_rtp_buffer_get_extension_bytes")]
344    pub fn extension_bytes(&self) -> Option<(u16, glib::Bytes)> {
345        unsafe {
346            let mut bits: u16 = 0;
347            Option::<glib::Bytes>::from_glib_full(ffi::gst_rtp_buffer_get_extension_bytes(
348                glib::translate::mut_override(&self.rtp_buffer),
349                &mut bits,
350            ))
351            .map(|bytes| (bits, bytes))
352        }
353    }
354
355    #[doc(alias = "get_extension_onebyte_header")]
356    #[doc(alias = "gst_rtp_buffer_get_extension_onebyte_header")]
357    pub fn extension_onebyte_header(&self, id: u8, nth: u32) -> Option<&[u8]> {
358        unsafe {
359            let mut data = ptr::null_mut();
360            // FIXME: Workaround for gstreamer-rtp-sys having the wrong type for this parameter
361            let data_ptr = &mut data as *mut *mut u8 as *mut u8;
362            let mut size: u32 = 0;
363            let result: bool = from_glib(ffi::gst_rtp_buffer_get_extension_onebyte_header(
364                glib::translate::mut_override(&self.rtp_buffer),
365                id,
366                nth,
367                data_ptr,
368                &mut size,
369            ));
370            if result {
371                if size == 0 {
372                    Some(&[])
373                } else {
374                    Some(slice::from_raw_parts(data as *const u8, size as usize))
375                }
376            } else {
377                None
378            }
379        }
380    }
381
382    #[doc(alias = "get_extension_twobytes_header")]
383    #[doc(alias = "gst_rtp_buffer_get_extension_twobytes_header")]
384    pub fn extension_twobytes_header(&self, id: u8, nth: u32) -> Option<(u8, &[u8])> {
385        unsafe {
386            let mut data = ptr::null_mut();
387            // FIXME: Workaround for gstreamer-rtp-sys having the wrong type for this parameter
388            let data_ptr = &mut data as *mut *mut u8 as *mut u8;
389            let mut size: u32 = 0;
390            let mut appbits = 0;
391            let result: bool = from_glib(ffi::gst_rtp_buffer_get_extension_twobytes_header(
392                glib::translate::mut_override(&self.rtp_buffer),
393                &mut appbits,
394                id,
395                nth,
396                data_ptr,
397                &mut size,
398            ));
399            if result {
400                if size == 0 {
401                    Some((appbits, &[]))
402                } else {
403                    Some((
404                        appbits,
405                        slice::from_raw_parts(data as *const u8, size as usize),
406                    ))
407                }
408            } else {
409                None
410            }
411        }
412    }
413
414    #[doc(alias = "get_padding")]
415    #[doc(alias = "gst_rtp_buffer_get_padding")]
416    pub fn has_padding(&self) -> bool {
417        unsafe {
418            from_glib(ffi::gst_rtp_buffer_get_padding(
419                glib::translate::mut_override(&self.rtp_buffer),
420            ))
421        }
422    }
423
424    #[inline]
425    pub fn as_ptr(&self) -> *const ffi::GstRTPBuffer {
426        &self.rtp_buffer as *const ffi::GstRTPBuffer
427    }
428
429    #[inline]
430    pub fn as_mut_ptr(&self) -> *mut ffi::GstRTPBuffer {
431        &self.rtp_buffer as *const ffi::GstRTPBuffer as *mut ffi::GstRTPBuffer
432    }
433}
434
435impl<T> Drop for RTPBuffer<'_, T> {
436    #[inline]
437    fn drop(&mut self) {
438        unsafe {
439            ffi::gst_rtp_buffer_unmap(&mut self.rtp_buffer);
440        }
441    }
442}
443
444pub trait RTPBufferExt {
445    fn new_rtp_with_sizes(
446        payload_len: u32,
447        pad_len: u8,
448        csrc_count: u8,
449    ) -> Result<gst::Buffer, glib::BoolError>;
450}
451
452impl RTPBufferExt for gst::Buffer {
453    fn new_rtp_with_sizes(
454        payload_len: u32,
455        pad_len: u8,
456        csrc_count: u8,
457    ) -> Result<gst::Buffer, glib::BoolError> {
458        assert_initialized_main_thread!();
459        unsafe {
460            Option::<_>::from_glib_full(ffi::gst_rtp_buffer_new_allocate(
461                payload_len,
462                pad_len,
463                csrc_count,
464            ))
465            .ok_or_else(|| glib::bool_error!("Failed to allocate new RTP buffer"))
466        }
467    }
468}
469
470#[doc(alias = "gst_rtp_buffer_compare_seqnum")]
471pub fn compare_seqnum(seqnum1: u16, seqnum2: u16) -> i32 {
472    skip_assert_initialized!();
473    unsafe { ffi::gst_rtp_buffer_compare_seqnum(seqnum1, seqnum2) }
474}
475
476#[doc(alias = "gst_rtp_buffer_calc_header_len")]
477pub fn calc_header_len(csrc_count: u8) -> u32 {
478    skip_assert_initialized!();
479    unsafe { ffi::gst_rtp_buffer_calc_header_len(csrc_count) }
480}
481
482#[doc(alias = "gst_rtp_buffer_calc_packet_len")]
483pub fn calc_packet_len(payload_len: u32, pad_len: u8, csrc_count: u8) -> u32 {
484    skip_assert_initialized!();
485    unsafe { ffi::gst_rtp_buffer_calc_packet_len(payload_len, pad_len, csrc_count) }
486}
487
488#[doc(alias = "gst_rtp_buffer_calc_payload_len")]
489pub fn calc_payload_len(packet_len: u32, pad_len: u8, csrc_count: u8) -> u32 {
490    skip_assert_initialized!();
491    unsafe { ffi::gst_rtp_buffer_calc_payload_len(packet_len, pad_len, csrc_count) }
492}
493
494#[doc(alias = "gst_rtp_buffer_ext_timestamp")]
495pub fn ext_timestamp(exttimestamp: &mut u64, timestamp: u32) -> u64 {
496    skip_assert_initialized!();
497    unsafe { ffi::gst_rtp_buffer_ext_timestamp(exttimestamp, timestamp) }
498}
499
500#[cfg(test)]
501mod tests {
502    use super::*;
503
504    #[test]
505    fn test_map() {
506        gst::init().unwrap();
507
508        let csrc_count = 2;
509        let payload_size = 16;
510        let mut buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
511        {
512            let buffer = buffer.get_mut().unwrap();
513            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
514
515            rtp_buffer.set_seq(42);
516            assert_eq!(rtp_buffer.seq(), 42);
517
518            rtp_buffer.set_marker(true);
519            assert!(rtp_buffer.is_marker());
520
521            rtp_buffer.set_payload_type(43);
522            assert_eq!(rtp_buffer.payload_type(), 43);
523
524            rtp_buffer.set_timestamp(44);
525            assert_eq!(rtp_buffer.timestamp(), 44);
526
527            rtp_buffer.set_ssrc(45);
528            assert_eq!(rtp_buffer.ssrc(), 45);
529
530            assert_eq!(rtp_buffer.payload_size(), payload_size);
531            let payload = rtp_buffer.payload();
532            assert!(payload.is_ok());
533            let payload = payload.unwrap();
534            assert_eq!(payload.len(), payload_size as usize);
535
536            assert_eq!(rtp_buffer.csrc_count(), csrc_count);
537            rtp_buffer.set_csrc(0, 12);
538            rtp_buffer.set_csrc(1, 15);
539            assert_eq!(rtp_buffer.csrc(0).unwrap(), 12);
540            assert_eq!(rtp_buffer.csrc(1).unwrap(), 15);
541            assert!(rtp_buffer.csrc(2).is_none());
542
543            rtp_buffer.set_extension(true);
544            assert!(rtp_buffer.is_extension());
545
546            assert_eq!(rtp_buffer.extension_bytes(), None);
547        }
548    }
549
550    #[test]
551    fn test_empty_payload() {
552        gst::init().unwrap();
553
554        let csrc_count = 0;
555        let payload_size = 0;
556        let buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
557        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
558
559        assert_eq!(rtp_buffer.payload_size(), payload_size);
560        let payload = rtp_buffer.payload();
561        assert!(payload.is_ok());
562        assert_eq!(payload.unwrap().len(), payload_size as usize);
563    }
564
565    #[test]
566    fn test_mut_payload() {
567        gst::init().unwrap();
568
569        let csrc_count = 2;
570        let payload_size = 8;
571        let mut buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
572        {
573            let buffer = buffer.get_mut().unwrap();
574            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
575
576            let payload = rtp_buffer.payload_mut();
577            assert!(payload.is_ok());
578
579            let payload = payload.unwrap();
580            payload[3] = 42;
581        }
582
583        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
584        let payload = rtp_buffer.payload();
585
586        assert!(payload.is_ok());
587        assert_eq!(payload.unwrap()[3], 42);
588    }
589
590    #[test]
591    fn test_extension_header_onebyte() {
592        gst::init().unwrap();
593
594        let extension_data: [u8; 4] = [100, 101, 102, 103];
595        let mut buffer = gst::Buffer::new_rtp_with_sizes(16, 4, 0).unwrap();
596        {
597            let buffer = buffer.get_mut().unwrap();
598            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
599
600            assert_eq!(rtp_buffer.extension_bytes(), None);
601
602            let result = rtp_buffer.add_extension_onebyte_header(1, &extension_data);
603            assert!(result.is_ok());
604        }
605
606        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
607        let bytes_option = rtp_buffer.extension_bytes();
608        assert!(bytes_option.is_some());
609        let (bits, bytes) = bytes_option.unwrap();
610        // 0xBEDE is the onebyte extension header marker: https://tools.ietf.org/html/rfc5285 (4.2)
611        assert_eq!(bits, 0xbede);
612        /*
613         * bytes is:
614         * * id (4 bits)
615         * * size-1 (4 bits)
616         * * data (with padded length to multiples of 4)
617         */
618        assert_eq!(bytes[0] >> 4, 1);
619        assert_eq!(bytes[0] & 0xF, 3);
620        for i in 0..extension_data.len() {
621            assert_eq!(bytes[i + 1], extension_data[i]);
622        }
623
624        let result = rtp_buffer.extension_onebyte_header(2, 0);
625        assert!(result.is_none());
626
627        let result = rtp_buffer.extension_onebyte_header(1, 0);
628        assert!(result.is_some());
629        assert_eq!(result.unwrap(), &extension_data);
630    }
631
632    #[test]
633    fn test_extension_header_twobytes() {
634        gst::init().unwrap();
635
636        let extension_data: [u8; 4] = [100, 101, 102, 103];
637        let appbits = 5;
638        let id = 1;
639
640        let mut buffer = gst::Buffer::new_rtp_with_sizes(16, 4, 0).unwrap();
641        {
642            let buffer = buffer.get_mut().unwrap();
643            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
644
645            assert_eq!(rtp_buffer.extension_bytes(), None);
646
647            let result = rtp_buffer.add_extension_twobytes_header(appbits, id, &extension_data);
648            assert!(result.is_ok());
649        }
650
651        let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
652
653        let bytes_option = rtp_buffer.extension_bytes();
654        assert!(bytes_option.is_some());
655        let (bits, bytes) = bytes_option.unwrap();
656        // 0x100 + appbits is the twobyte extension header marker:
657        // https://tools.ietf.org/html/rfc5285 (4.3)
658        assert_eq!(bits, 0x1000 | appbits as u16);
659        /*
660         * bytes is:
661         * * id (1 byte)
662         * * size-2 (1 byte)
663         * * data (with padded length to multiples of 4)
664         */
665        assert_eq!(bytes[0], id);
666        assert_eq!(bytes[1], extension_data.len() as u8);
667        for i in 0..extension_data.len() {
668            assert_eq!(bytes[i + 2], extension_data[i]);
669        }
670
671        let result = rtp_buffer.extension_twobytes_header(2, 0);
672        assert!(result.is_none());
673
674        let result = rtp_buffer.extension_twobytes_header(id, 0);
675        assert!(result.is_some());
676        let (extracted_appbits, data) = result.unwrap();
677        assert_eq!(appbits, extracted_appbits);
678        assert_eq!(data, &extension_data);
679    }
680
681    #[test]
682    fn test_padding() {
683        gst::init().unwrap();
684
685        let csrc_count = 2;
686        let payload_size = 16;
687        let mut buffer = gst::Buffer::new_rtp_with_sizes(payload_size, 4, csrc_count).unwrap();
688        {
689            let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
690            assert!(rtp_buffer.has_padding());
691        }
692        {
693            let buffer = buffer.get_mut().unwrap();
694            let mut rtp_buffer = RTPBuffer::from_buffer_writable(buffer).unwrap();
695
696            rtp_buffer.set_padding(false);
697        }
698
699        {
700            let rtp_buffer = RTPBuffer::from_buffer_readable(&buffer).unwrap();
701            assert!(!rtp_buffer.has_padding());
702        }
703    }
704
705    #[test]
706    fn test_calc_functions() {
707        let res = super::calc_header_len(0);
708        assert_eq!(res, 12);
709        let res = super::calc_packet_len(100, 10, 2);
710        assert_eq!(res, 130);
711        let res = super::calc_payload_len(100, 5, 4);
712        assert_eq!(res, 67);
713    }
714}