rtp_parse/rtcp/
rtcp_rr.rs

1use anyhow::{Context, Result};
2use bit_cursor::{
3    bit_read::BitRead, bit_read_exts::BitReadExts, bit_write::BitWrite,
4    bit_write_exts::BitWriteExts, byte_order::NetworkOrder,
5};
6
7use crate::rtcp::rtcp_report_block::read_rtcp_report_block;
8
9use super::{
10    rtcp_header::{write_rtcp_header, RtcpHeader},
11    rtcp_report_block::{write_rtcp_report_block, RtcpReportBlock},
12};
13
14/// https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.2
15///         0                   1                   2                   3
16///         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
17///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18/// header |V=2|P|    RC   |   PT=RR=201   |             length            |
19///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20///        |                     SSRC of packet sender                     |
21///        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
22/// report |                 SSRC_1 (SSRC of first source)                 |
23/// block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24///   1    | fraction lost |       cumulative number of packets lost       |
25///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26///        |           extended highest sequence number received           |
27///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28///        |                      interarrival jitter                      |
29///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30///        |                         last SR (LSR)                         |
31///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32///        |                   delay since last SR (DLSR)                  |
33///        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
34/// report |                 SSRC_2 (SSRC of second source)                |
35/// block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36///   2    :                               ...                             :
37///        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
38///        |                  profile-specific extensions                  |
39///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40///
41#[derive(Debug)]
42pub struct RtcpRrPacket {
43    pub header: RtcpHeader,
44    pub sender_ssrc: u32,
45    pub report_blocks: Vec<RtcpReportBlock>,
46}
47
48impl RtcpRrPacket {
49    pub const PT: u8 = 201;
50}
51
52pub fn read_rtcp_rr<R: BitRead>(buf: &mut R, header: RtcpHeader) -> Result<RtcpRrPacket> {
53    let sender_ssrc = buf.read_u32::<NetworkOrder>().context("sender ssrc")?;
54    let report_blocks = (0u32..header.report_count.into())
55        .map(|i| read_rtcp_report_block(buf).with_context(|| format!("report block {i}")))
56        .collect::<Result<Vec<RtcpReportBlock>>>()
57        .context("report blocks")?;
58
59    Ok(RtcpRrPacket {
60        header,
61        sender_ssrc,
62        report_blocks,
63    })
64}
65
66pub fn write_rtcp_rr<W: BitWrite>(buf: &mut W, packet: &RtcpRrPacket) -> Result<()> {
67    write_rtcp_header(buf, &packet.header).context("header")?;
68    buf.write_u32::<NetworkOrder>(packet.sender_ssrc)
69        .context("sender ssrc")?;
70    packet
71        .report_blocks
72        .iter()
73        .enumerate()
74        .map(|(i, rb)| {
75            write_rtcp_report_block(buf, rb).with_context(|| format!("report block {i}"))
76        })
77        .collect::<Result<Vec<()>>>()
78        .context("report blocks")?;
79    Ok(())
80}