rtp_parse/rtcp/
rtcp_fb_fir.rs

1use parsely_rs::*;
2
3use super::{
4    rtcp_fb_header::RtcpFbHeader, rtcp_fb_packet::RtcpFbPsPacket, rtcp_header::RtcpHeader,
5};
6
7/// FIR FCI:
8///
9///  0                   1                   2                   3
10///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
11/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12/// |                              SSRC                             |
13/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14/// | Seq nr.       |    Reserved                                   |
15/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16///
17/// From https://datatracker.ietf.org/doc/html/rfc5104#section-4.3.1.2:
18/// Within the common packet header for feedback messages (as defined in
19/// section 6.1 of [RFC4585]), the "SSRC of packet sender" field
20/// indicates the source of the request, and the "SSRC of media source"
21/// is not used and SHALL be set to 0.  The SSRCs of the media senders to
22/// which the FIR command applies are in the corresponding FCI entries.
23/// A FIR message MAY contain requests to multiple media senders, using
24/// one FCI entry per target media sender.
25#[derive(Debug, ParselyRead, ParselyWrite, PartialEq)]
26#[parsely_read(required_context("header: RtcpHeader", "fb_header: RtcpFbHeader"))]
27pub struct RtcpFbFirPacket {
28    #[parsely_read(assign_from = "header")]
29    #[parsely(assertion = "|header: &RtcpHeader| header.report_count == RtcpFbFirPacket::FMT")]
30    #[parsely_write(sync_with("self.payload_length_bytes()", "RtcpFbFirPacket::FMT"))]
31    pub header: RtcpHeader,
32    #[parsely_read(assign_from = "fb_header")]
33    #[parsely(assertion = "|fb_header: &RtcpFbHeader| fb_header.media_source_ssrc == 0")]
34    pub fb_header: RtcpFbHeader,
35    #[parsely_read(while_pred = "buf.remaining_bytes() > 0")]
36    pub fcis: Vec<RtcpFbFirFci>,
37}
38
39impl RtcpFbFirPacket {
40    pub const FMT: u5 = u5::new(4);
41
42    pub fn add_fci(mut self, fci: RtcpFbFirFci) -> Self {
43        self.fcis.push(fci);
44        self
45    }
46
47    pub fn payload_length_bytes(&self) -> u16 {
48        // 8 bytes per FCI
49        (self.fcis.len() * 8) as u16
50    }
51}
52
53impl Default for RtcpFbFirPacket {
54    fn default() -> Self {
55        Self {
56            header: RtcpHeader::default()
57                .packet_type(RtcpFbPsPacket::PT)
58                .report_count(RtcpFbFirPacket::FMT),
59            fb_header: RtcpFbHeader::default().media_source_ssrc(0),
60            fcis: Default::default(),
61        }
62    }
63}
64
65#[derive(Debug, ParselyRead, ParselyWrite, PartialEq)]
66pub struct RtcpFbFirFci {
67    ssrc: u32,
68    seq_num: u8,
69    _reserved: u24,
70}
71
72impl RtcpFbFirFci {
73    pub const SIZE_BYTES: usize = 8;
74
75    pub fn new(ssrc: u32, seq_num: u8) -> Self {
76        Self {
77            ssrc,
78            seq_num,
79            _reserved: u24::new(0),
80        }
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::rtcp::rtcp_fb_packet::RtcpFbPsPacket;
87
88    use super::*;
89
90    #[test]
91    fn test_read_fci() {
92        #[rustfmt::skip]
93        let data = vec![
94            // ssrc (42)
95            0x00, 0x00, 0x00, 0x2a,
96            // seq_num (1)
97            0x01,
98            // reserved
99            0x00, 0x00, 0x00
100        ];
101
102        let mut buf = Bits::from_owner_bytes(data);
103
104        let fci = RtcpFbFirFci::read::<NetworkOrder>(&mut buf, ()).expect("successful read");
105        assert_eq!(fci.ssrc, 42);
106        assert_eq!(fci.seq_num, 1);
107    }
108
109    #[test]
110    fn test_write_fci() {
111        let fci = RtcpFbFirFci::new(42, 1);
112        let mut buf_mut = BitsMut::new();
113
114        fci.write::<NetworkOrder>(&mut buf_mut, ())
115            .expect("successful write");
116        let mut buf = buf_mut.freeze();
117        let read_fci = RtcpFbFirFci::read::<NetworkOrder>(&mut buf, ()).expect("successful read");
118        assert_eq!(fci, read_fci);
119    }
120
121    #[test]
122    fn test_read_rtcp_fb_fir_packet() {
123        #[rustfmt::skip]
124        let data = vec![
125            // ssrc (42)
126            0x00, 0x00, 0x00, 0x2a,
127            // seq_num (1)
128            0x01,
129            // reserved
130            0x00, 0x00, 0x00
131        ];
132        let mut buf = Bits::from_owner_bytes(data);
133        let header = RtcpHeader {
134            report_count: RtcpFbFirPacket::FMT,
135            packet_type: RtcpFbPsPacket::PT,
136            length_field: 4,
137            ..Default::default()
138        };
139        let fb_header = RtcpFbHeader::new(42, 0);
140
141        let fb_fir_packet = RtcpFbFirPacket::read::<NetworkOrder>(&mut buf, (header, fb_header))
142            .expect("successful read");
143        assert_eq!(buf.remaining_bytes(), 0);
144        assert_eq!(fb_fir_packet.fcis.len(), 1);
145        let fci = &fb_fir_packet.fcis[0];
146        assert_eq!(fci.ssrc, 42);
147        assert_eq!(fci.seq_num, 1);
148    }
149
150    #[test]
151    fn test_read_rtcp_fb_fir_packet_multiple_fcis() {
152        #[rustfmt::skip]
153        let data = vec![
154            // ssrc (42)
155            0x00, 0x00, 0x00, 0x2a,
156            // seq_num (1)
157            0x01,
158            // reserved
159            0x00, 0x00, 0x00,
160            // ssrc (43)
161            0x00, 0x00, 0x00, 0x2b,
162            // seq_num (2)
163            0x02,
164            // reserved
165            0x00, 0x00, 0x00,
166        ];
167        let mut buf = Bits::from_owner_bytes(data);
168        let header = RtcpHeader {
169            report_count: RtcpFbFirPacket::FMT,
170            packet_type: RtcpFbPsPacket::PT,
171            length_field: 6,
172            ..Default::default()
173        };
174        let fb_header = RtcpFbHeader::new(42, 0);
175
176        let fb_fir_packet = RtcpFbFirPacket::read::<NetworkOrder>(&mut buf, (header, fb_header))
177            .expect("successful read");
178        assert_eq!(buf.remaining_bytes(), 0);
179        assert_eq!(fb_fir_packet.fcis.len(), 2);
180        let fci = &fb_fir_packet.fcis[0];
181        assert_eq!(fci.ssrc, 42);
182        assert_eq!(fci.seq_num, 1);
183        let fci = &fb_fir_packet.fcis[1];
184        assert_eq!(fci.ssrc, 43);
185        assert_eq!(fci.seq_num, 2);
186    }
187
188    #[test]
189    fn test_default() {
190        let rtcp_fb_fir = RtcpFbFirPacket::default();
191        assert_eq!(RtcpFbPsPacket::PT, rtcp_fb_fir.header.packet_type);
192        assert_eq!(RtcpFbFirPacket::FMT, rtcp_fb_fir.header.report_count);
193        assert_eq!(0, rtcp_fb_fir.fb_header.media_source_ssrc);
194    }
195
196    #[test]
197    fn test_sync() {
198        let mut rtcp_fb_fir = RtcpFbFirPacket::default()
199            .add_fci(RtcpFbFirFci::new(42, 1))
200            .add_fci(RtcpFbFirFci::new(43, 2));
201
202        rtcp_fb_fir.sync(()).expect("successful sync");
203        assert_eq!(RtcpFbPsPacket::PT, rtcp_fb_fir.header.packet_type);
204        assert_eq!(RtcpFbFirPacket::FMT, rtcp_fb_fir.header.report_count);
205        assert_eq!(0, rtcp_fb_fir.fb_header.media_source_ssrc);
206    }
207
208    #[test]
209    fn test_write() {
210        let mut rtcp_fb_fir = RtcpFbFirPacket::default()
211            .add_fci(RtcpFbFirFci::new(42, 1))
212            .add_fci(RtcpFbFirFci::new(43, 2));
213        rtcp_fb_fir.sync(()).unwrap();
214        let mut buf_mut = BitsMut::new();
215
216        rtcp_fb_fir.write::<NetworkOrder>(&mut buf_mut, ()).unwrap();
217        let mut buf = buf_mut.freeze();
218
219        let rtcp_header = RtcpHeader::read::<NetworkOrder>(&mut buf, ()).unwrap();
220        let rtcp_fb_header = RtcpFbHeader::read::<NetworkOrder>(&mut buf, ()).unwrap();
221        let read_rtcp_fb_fir =
222            RtcpFbFirPacket::read::<NetworkOrder>(&mut buf, (rtcp_header, rtcp_fb_header)).unwrap();
223        assert_eq!(rtcp_fb_fir, read_rtcp_fb_fir);
224    }
225}