rtcp_types/feedback/
pli.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use crate::feedback::FciFeedbackPacketType;
4use crate::{prelude::*, RtcpParseError, RtcpWriteError};
5
6/// Picture Loss Information as specified in RFC 4585
7#[derive(Debug)]
8pub struct Pli<'a> {
9    _data: &'a [u8],
10}
11
12impl Pli<'_> {
13    /// Construct a builder for a [`Pli`] packet.
14    pub fn builder() -> PliBuilder {
15        PliBuilder {}
16    }
17}
18
19impl<'a> FciParser<'a> for Pli<'a> {
20    const PACKET_TYPE: FciFeedbackPacketType = FciFeedbackPacketType::PAYLOAD;
21    const FCI_FORMAT: u8 = 1;
22
23    fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
24        if !data.is_empty() {
25            return Err(RtcpParseError::TooLarge {
26                expected: 0,
27                actual: data.len(),
28            });
29        }
30        Ok(Self { _data: data })
31    }
32}
33
34/// Builder for Picture Loss Information
35#[derive(Debug)]
36pub struct PliBuilder {}
37
38impl FciBuilder<'_> for PliBuilder {
39    fn format(&self) -> u8 {
40        1
41    }
42
43    fn supports_feedback_type(&self) -> FciFeedbackPacketType {
44        FciFeedbackPacketType::PAYLOAD
45    }
46}
47
48impl RtcpPacketWriter for PliBuilder {
49    fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
50        Ok(0)
51    }
52
53    fn write_into_unchecked(&self, _buf: &mut [u8]) -> usize {
54        0
55    }
56
57    fn get_padding(&self) -> Option<u8> {
58        None
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use crate::feedback::{PayloadFeedback, TransportFeedback};
66
67    #[test]
68    fn pli_build_parse() {
69        const REQ_LEN: usize = PayloadFeedback::MIN_PACKET_LEN;
70        let mut data = [0; REQ_LEN];
71        let pli = {
72            let fci = Pli::builder();
73            PayloadFeedback::builder_owned(fci)
74                .sender_ssrc(0x98765432)
75                .media_ssrc(0x10fedcba)
76        };
77        assert_eq!(pli.calculate_size().unwrap(), REQ_LEN);
78        let len = pli.write_into(&mut data).unwrap();
79        assert_eq!(len, REQ_LEN);
80        assert_eq!(
81            data,
82            [0x81, 0xce, 0x00, 0x02, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba,]
83        );
84
85        let fb = PayloadFeedback::parse(&data).unwrap();
86
87        assert_eq!(fb.sender_ssrc(), 0x98765432);
88        assert_eq!(fb.media_ssrc(), 0x10fedcba);
89        let _pli = fb.parse_fci::<Pli>().unwrap();
90    }
91
92    #[test]
93    fn pli_build_ref() {
94        const REQ_LEN: usize = PayloadFeedback::MIN_PACKET_LEN;
95        let mut data = [0; REQ_LEN];
96        let fci = Pli::builder();
97        let pli = PayloadFeedback::builder(&fci)
98            .sender_ssrc(0x98765432)
99            .media_ssrc(0x10fedcba);
100        assert_eq!(pli.calculate_size().unwrap(), REQ_LEN);
101        let len = pli.write_into(&mut data).unwrap();
102        assert_eq!(len, REQ_LEN);
103        assert_eq!(
104            data,
105            [0x81, 0xce, 0x00, 0x02, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba,]
106        );
107    }
108
109    #[test]
110    fn pli_parse_wrong_packet() {
111        let fb = TransportFeedback::parse(&[
112            0x81, 0xcd, 0x00, 0x02, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba,
113        ])
114        .unwrap();
115        assert!(matches!(
116            fb.parse_fci::<Pli>(),
117            Err(RtcpParseError::WrongImplementation),
118        ));
119    }
120
121    #[test]
122    fn pli_build_wrong_packet_type() {
123        const REQ_LEN: usize = TransportFeedback::MIN_PACKET_LEN;
124        let mut data = [0; REQ_LEN];
125        let fci = Pli::builder();
126        let pli = TransportFeedback::builder(&fci)
127            .sender_ssrc(0x98765432)
128            .media_ssrc(0x10fedcba);
129        assert!(matches!(
130            pli.calculate_size(),
131            Err(RtcpWriteError::FciWrongFeedbackPacketType)
132        ));
133        assert!(matches!(
134            pli.write_into(&mut data),
135            Err(RtcpWriteError::FciWrongFeedbackPacketType)
136        ));
137    }
138
139    #[test]
140    fn pli_parse_with_data() {
141        let pli = PayloadFeedback::parse(&[
142            0x81, 0xce, 0x00, 0x03, 0x98, 0x76, 0x54, 0x32, 0x10, 0xfe, 0xdc, 0xba, 0x00, 0x00,
143            0x00, 0x00,
144        ])
145        .unwrap();
146        assert!(matches!(
147            pli.parse_fci::<Pli>(),
148            Err(RtcpParseError::TooLarge {
149                expected: 0,
150                actual: 4
151            })
152        ));
153    }
154}