rtp_parse/rtcp/rtcp_report_block.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, nsw_types::*,
5};
6
7/// https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.1
8/// 0 1 2 3
9/// 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
10/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11/// header |V=2|P| RC | PT=SR=200 | length |
12/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13/// | SSRC of sender |
14/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
15/// sender | NTP timestamp, most significant word |
16/// info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17/// | NTP timestamp, least significant word |
18/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19/// | RTP timestamp |
20/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21/// | sender's packet count |
22/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23/// | sender's octet count |
24/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
25/// report | SSRC_1 (SSRC of first source) |
26/// block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27/// 1 | fraction lost | cumulative number of packets lost |
28/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29/// | extended highest sequence number received |
30/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31/// | interarrival jitter |
32/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33/// | last SR (LSR) |
34/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35/// | delay since last SR (DLSR) |
36/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
37/// report | SSRC_2 (SSRC of second source) |
38/// block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39/// 2 : ... :
40/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
41/// | profile-specific extensions |
42/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43#[derive(Debug)]
44pub struct RtcpReportBlock {
45 pub ssrc: u32,
46 pub fraction_lost: u8,
47 pub cumulative_lost: u24,
48 pub extended_highest_seq_num: u32,
49 pub interarrival_jitter: u32,
50 pub last_sr_timestamp: u32,
51 pub delay_since_last_sr: u32,
52}
53
54pub fn read_rtcp_report_block<R: BitRead>(buf: &mut R) -> Result<RtcpReportBlock> {
55 Ok(RtcpReportBlock {
56 ssrc: buf.read_u32::<NetworkOrder>().context("ssrc")?,
57 fraction_lost: buf.read_u8().context("fraction_lost")?,
58 cumulative_lost: buf.read_u24::<NetworkOrder>().context("fraction_lost")?,
59 extended_highest_seq_num: buf.read_u32::<NetworkOrder>().context("cumulative_lost")?,
60 interarrival_jitter: buf
61 .read_u32::<NetworkOrder>()
62 .context("interarrival_jitter")?,
63 last_sr_timestamp: buf
64 .read_u32::<NetworkOrder>()
65 .context("last_sr_timestamp")?,
66 delay_since_last_sr: buf
67 .read_u32::<NetworkOrder>()
68 .context("delay_since_last_sr")?,
69 })
70}
71
72pub fn write_rtcp_report_block<W: BitWrite>(
73 buf: &mut W,
74 rtcp_report_block: &RtcpReportBlock,
75) -> Result<()> {
76 buf.write_u32::<NetworkOrder>(rtcp_report_block.ssrc)
77 .context("ssrc")?;
78 buf.write_u8(rtcp_report_block.fraction_lost)
79 .context("fraction_lost")?;
80 buf.write_u24::<NetworkOrder>(rtcp_report_block.cumulative_lost)
81 .context("cumulative_lost")?;
82 buf.write_u32::<NetworkOrder>(rtcp_report_block.extended_highest_seq_num)
83 .context("extended_highest_seq_num")?;
84 buf.write_u32::<NetworkOrder>(rtcp_report_block.interarrival_jitter)
85 .context("interarrival_jitter")?;
86 buf.write_u32::<NetworkOrder>(rtcp_report_block.last_sr_timestamp)
87 .context("last_sr_timestamp")?;
88 buf.write_u32::<NetworkOrder>(rtcp_report_block.delay_since_last_sr)
89 .context("delay_since_last_sr")?;
90
91 Ok(())
92}