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}