rtp_parse/rtcp/rtcp_sr.rs
1use std::fmt::Debug;
2
3use anyhow::{Context, Result};
4use bit_cursor::{
5 bit_read_exts::BitReadExts, bit_write::BitWrite, bit_write_exts::BitWriteExts,
6 byte_order::NetworkOrder,
7};
8
9use crate::{
10 rtcp::{
11 rtcp_header::write_rtcp_header,
12 rtcp_report_block::{read_rtcp_report_block, write_rtcp_report_block},
13 rtcp_sender_info::{read_rtcp_sender_info, write_rtcp_sender_info},
14 },
15 PacketBuffer,
16};
17
18use super::{
19 rtcp_header::RtcpHeader, rtcp_report_block::RtcpReportBlock, rtcp_sender_info::RtcpSenderInfo,
20};
21
22/// https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.1
23/// 0 1 2 3
24/// 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
25/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26/// header |V=2|P| RC | PT=SR=200 | length |
27/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28/// | SSRC of sender |
29/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
30/// sender | NTP timestamp, most significant word |
31/// info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32/// | NTP timestamp, least significant word |
33/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34/// | RTP timestamp |
35/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36/// | sender's packet count |
37/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38/// | sender's octet count |
39/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
40/// report | SSRC_1 (SSRC of first source) |
41/// block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42/// 1 | fraction lost | cumulative number of packets lost |
43/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44/// | extended highest sequence number received |
45/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46/// | interarrival jitter |
47/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48/// | last SR (LSR) |
49/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50/// | delay since last SR (DLSR) |
51/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
52/// report | SSRC_2 (SSRC of second source) |
53/// block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54/// 2 : ... :
55/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
56/// | profile-specific extensions |
57/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58#[derive(Debug)]
59pub struct RtcpSrPacket {
60 pub header: RtcpHeader,
61 pub sender_ssrc: u32,
62 pub sender_info: RtcpSenderInfo,
63 pub report_blocks: Vec<RtcpReportBlock>,
64}
65
66impl RtcpSrPacket {
67 pub const PT: u8 = 200;
68}
69
70pub fn read_rtcp_sr<B: PacketBuffer>(buf: &mut B, header: RtcpHeader) -> Result<RtcpSrPacket> {
71 let sender_ssrc = buf.read_u32::<NetworkOrder>().context("sender ssrc")?;
72 let sender_info = read_rtcp_sender_info(buf).context("sender info")?;
73 let report_blocks = (0u32..header.report_count.into())
74 .map(|i| read_rtcp_report_block(buf).with_context(|| format!("report block {i}")))
75 .collect::<Result<Vec<RtcpReportBlock>>>()
76 .context("report blocks")?;
77
78 Ok(RtcpSrPacket {
79 header,
80 sender_ssrc,
81 sender_info,
82 report_blocks,
83 })
84}
85
86pub fn write_rtcp_sr<W: BitWrite>(buf: &mut W, packet: &RtcpSrPacket) -> Result<()> {
87 write_rtcp_header(buf, &packet.header).context("header")?;
88 buf.write_u32::<NetworkOrder>(packet.sender_ssrc)
89 .context("sender ssrc")?;
90 write_rtcp_sender_info(buf, &packet.sender_info).context("sender info")?;
91 packet
92 .report_blocks
93 .iter()
94 .enumerate()
95 .map(|(i, rb)| {
96 write_rtcp_report_block(buf, rb).with_context(|| format!("report block {i}"))
97 })
98 .collect::<Result<Vec<()>>>()
99 .context("report blocks")?;
100 todo!()
101}