rtp_parse/rtcp/
rtcp_header.rs1use std::fmt::{Debug, LowerHex};
2
3use anyhow::{anyhow, Context, Result};
4use bit_cursor::{
5 bit_read::BitRead, bit_read_exts::BitReadExts, bit_write::BitWrite,
6 bit_write_exts::BitWriteExts, byte_order::NetworkOrder, nsw_types::*,
7};
8
9#[derive(Debug, PartialEq, Eq)]
23pub struct RtcpHeader {
24 pub version: u2,
25 pub has_padding: bool,
26 pub report_count: u5,
27 pub packet_type: u8,
28 pub length_field: u16,
29}
30
31pub fn get_sender_ssrc(buf: &[u8]) -> u32 {
36 u32::from_be_bytes(buf[4..8].try_into().unwrap())
37}
38
39impl RtcpHeader {
40 pub const SIZE_BYTES: usize = 4;
41
42 pub fn payload_length_bytes(&self) -> Result<u16> {
44 self.length_field
45 .checked_mul(4)
46 .ok_or(anyhow!("Invalid length field"))
47 }
48}
49
50pub fn read_rtcp_header<R: BitRead + Debug + LowerHex>(buf: &mut R) -> Result<RtcpHeader> {
51 Ok(RtcpHeader {
52 version: buf.read_u2().context("version")?,
53 has_padding: buf.read_bool().context("has_padding")?,
54 report_count: buf.read_u5().context("report_count")?,
55 packet_type: buf.read_u8().context("packet_type")?,
56 length_field: buf.read_u16::<NetworkOrder>().context("length_field")?,
57 })
58}
59
60pub fn write_rtcp_header<W: BitWrite>(buf: &mut W, header: &RtcpHeader) -> Result<()> {
61 buf.write_u2(header.version).context("version")?;
62 buf.write_bool(header.has_padding).context("has_padding")?;
63 buf.write_u5(header.report_count).context("report_count")?;
64 buf.write_u8(header.packet_type).context("packet_type")?;
65 buf.write_u16::<NetworkOrder>(header.length_field)
66 .context("length_field")?;
67
68 Ok(())
69}
70
71#[cfg(test)]
72#[allow(clippy::unusual_byte_groupings, clippy::bool_assert_comparison)]
73mod tests {
74 use bit_cursor::bit_cursor::BitCursor;
75 use bitvec::{order::Msb0, vec::BitVec};
76
77 use super::*;
78
79 #[test]
80 fn test_read_rtcp_header() {
81 let data: Vec<u8> = vec![0b10_0_00001, 202, 0, 42];
82 let mut cursor = BitCursor::new(BitVec::<_, Msb0>::from_vec(data));
83
84 let header = read_rtcp_header(&mut cursor)
85 .context("rtcp header")
86 .unwrap();
87 assert_eq!(header.version, u2::new(2));
88 assert_eq!(header.has_padding, false);
89 assert_eq!(header.report_count, u5::new(1));
90 assert_eq!(header.packet_type, 202);
91 assert_eq!(header.length_field, 42);
92 }
93
94 #[test]
95 fn test_write_rtcp_header() {
96 let header = RtcpHeader {
97 version: u2::new(1),
98 has_padding: false,
99 report_count: u5::new(1),
100 packet_type: 1,
101 length_field: 2,
102 };
103
104 let data: Vec<u8> = vec![0; 4];
105 let bv = BitVec::<_, Msb0>::from_vec(data);
106 let mut cursor = BitCursor::new(bv);
107
108 write_rtcp_header(&mut cursor, &header).expect("successful write");
109 let data = cursor.into_inner();
110
111 let mut read_cursor = BitCursor::new(data);
112 let read_header = read_rtcp_header(&mut read_cursor)
113 .context("rtcp header")
114 .unwrap();
115 assert_eq!(header, read_header);
116 }
117}