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}