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