Skip to main content

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