atm0s_custom_str0m/rtp/rtcp/
fir.rs

1use super::list::private::WordSized;
2use super::{FeedbackMessageType, PayloadType, ReportList, RtcpHeader, RtcpPacket, RtcpType, Ssrc};
3
4/// Full Intra Request (FIR).
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct Fir {
7    /// Sender of this feedback. Mostly irrelevant, but part of RTCP packets.
8    pub sender_ssrc: Ssrc,
9    /// The SSRC needing a full codec restart.
10    pub reports: ReportList<FirEntry>,
11}
12
13/// Entry reported needing a codec restart.
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct FirEntry {
16    /// The SSRC needing a full codec restart.
17    pub ssrc: Ssrc,
18    /// Counter keeping track of which restart request this is.
19    pub seq_no: u8,
20}
21
22impl RtcpPacket for Fir {
23    fn header(&self) -> RtcpHeader {
24        RtcpHeader {
25            rtcp_type: RtcpType::PayloadSpecificFeedback,
26            feedback_message_type: FeedbackMessageType::PayloadFeedback(
27                PayloadType::FullIntraRequest,
28            ),
29            words_less_one: (self.length_words() - 1) as u16,
30        }
31    }
32
33    fn length_words(&self) -> usize {
34        // header
35        // sender SSRC
36        // media SSRC (set to 0)
37        // reports * FirEntry: SSRC + seqNo
38        1 + 1 + 1 + self.reports.len() * 2
39    }
40
41    fn write_to(&self, buf: &mut [u8]) -> usize {
42        self.header().write_to(&mut buf[..4]);
43
44        buf[4..8].copy_from_slice(&self.sender_ssrc.to_be_bytes());
45
46        let media_ssrc = self.reports.iter().next().map(|s| *s.ssrc).unwrap_or(0);
47        buf[8..12].copy_from_slice(&media_ssrc.to_be_bytes());
48
49        let mut buf = &mut buf[12..];
50        for r in &self.reports {
51            buf[0..4].copy_from_slice(&r.ssrc.to_be_bytes());
52            buf[4..8].copy_from_slice(&[r.seq_no, 0, 0, 0]);
53            buf = &mut buf[8..];
54        }
55
56        4 + 4 + 4 + self.reports.len() * 8
57    }
58}
59
60impl WordSized for FirEntry {
61    fn word_size(&self) -> usize {
62        2
63    }
64}
65
66impl<'a> TryFrom<&'a [u8]> for Fir {
67    type Error = &'static str;
68
69    fn try_from(buf: &'a [u8]) -> Result<Self, Self::Error> {
70        if buf.len() < 16 {
71            return Err("Fir less than 16 bytes");
72        }
73
74        let sender_ssrc = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]).into();
75
76        let mut reports = ReportList::new();
77
78        let mut buf = &buf[8..];
79        let count = buf.len() / 8;
80        let max = count.min(31);
81
82        for _ in 0..max {
83            let ssrc = u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]).into();
84            let seq_no = buf[4];
85            reports.push(FirEntry { ssrc, seq_no });
86            buf = &buf[8..];
87        }
88
89        Ok(Fir {
90            sender_ssrc,
91            reports,
92        })
93    }
94}