rtp_parse/rtcp/
rtcp_bye.rs1use std::str::from_utf8;
2
3use anyhow::{Context, Result};
4use bit_cursor::{
5 bit_read::BitRead, bit_read_exts::BitReadExts, bit_write::BitWrite,
6 bit_write_exts::BitWriteExts, byte_order::NetworkOrder,
7};
8
9use super::rtcp_header::{write_rtcp_header, RtcpHeader};
10
11#[derive(Debug)]
24pub struct RtcpByePacket {
25 pub header: RtcpHeader,
26 pub ssrcs: Vec<u32>,
27 pub reason: Option<String>,
28}
29
30impl RtcpByePacket {
31 pub const PT: u8 = 203;
32}
33
34pub fn read_rtcp_bye<R: BitRead>(buf: &mut R, header: RtcpHeader) -> Result<RtcpByePacket> {
35 let ssrcs = (0u32..header.report_count.into())
36 .map(|i| {
37 buf.read_u32::<NetworkOrder>()
38 .with_context(|| format!("ssrc-{i}"))
39 })
40 .collect::<Result<Vec<u32>>>()?;
41
42 let reason = {
44 if let Ok(reason_length) = buf.read_u8() {
45 let mut reason_bytes = vec![0; reason_length.into()];
46 std::io::Read::read(buf, &mut reason_bytes).context("bye reason bytes")?;
47 Some(
48 from_utf8(&reason_bytes)
49 .context("convert bye reason from urf8")
50 .map(|str| str.to_owned())?,
51 )
52 } else {
53 None
57 }
58 };
59 Ok(RtcpByePacket {
60 header,
61 ssrcs,
62 reason,
63 })
64}
65
66pub fn write_rtcp_bye<W: BitWrite>(buf: &mut W, packet: &RtcpByePacket) -> Result<()> {
67 write_rtcp_header(buf, &packet.header).context("header")?;
68 packet
69 .ssrcs
70 .iter()
71 .enumerate()
72 .map(|(i, ssrc)| {
73 buf.write_u32::<NetworkOrder>(*ssrc)
74 .with_context(|| format!("ssrc-{i}"))
75 })
76 .collect::<Result<Vec<()>>>()
77 .context("ssrcs")?;
78
79 if let Some(reason) = &packet.reason {
80 let utf8_bytes = reason.as_bytes();
81 buf.write_u8(utf8_bytes.len() as u8)
82 .context("reason length")?;
83 std::io::Write::write(buf, utf8_bytes).context("reason string")?;
84 }
85
86 Ok(())
87}
88
89#[cfg(test)]
90mod tests {
91 use bit_cursor::{bit_cursor::BitCursor, nsw_types::*};
92 use bitvec::{order::Msb0, vec::BitVec};
93
94 use super::*;
95
96 #[test]
97 fn test_parse_success() {
98 let rtcp_header = RtcpHeader {
99 version: u2::new(2),
100 has_padding: false,
101 report_count: u5::new(2),
102 packet_type: 203,
103 length_field: 2,
104 };
105 let reason_str = "goodbye";
106 let reason_bytes = reason_str.bytes();
107 #[rustfmt::skip]
108 let mut payload = vec![
109 0x00, 0x00, 0x00, 0x01,
111 0x00, 0x00, 0x00, 0x02,
113 reason_bytes.len() as u8
115 ];
116 payload.extend(reason_bytes.collect::<Vec<u8>>());
118 let mut buf = BitCursor::new(BitVec::<_, Msb0>::from_vec(payload));
119 let rtcp_bye = read_rtcp_bye(&mut buf, rtcp_header).unwrap();
120 assert!(rtcp_bye.ssrcs.contains(&1u32));
121 assert!(rtcp_bye.ssrcs.contains(&2u32));
122 assert_eq!(rtcp_bye.reason.unwrap(), reason_str);
123 }
124
125 #[test]
126 fn test_parse_success_no_reason() {
127 let rtcp_header = RtcpHeader {
128 version: u2::new(2),
129 has_padding: false,
130 report_count: u5::new(2),
131 packet_type: 203,
132 length_field: 2,
133 };
134 let payload = vec![
135 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
138 ];
139 let mut buf = BitCursor::new(BitVec::<u8, Msb0>::from_vec(payload));
140 let rtcp_bye = read_rtcp_bye(&mut buf, rtcp_header).unwrap();
141 assert!(rtcp_bye.ssrcs.contains(&1u32));
142 assert!(rtcp_bye.ssrcs.contains(&2u32));
143 assert!(rtcp_bye.reason.is_none());
144 }
145
146 #[test]
147 fn test_missing_ssrc() {
148 let rtcp_header = RtcpHeader {
149 version: u2::new(2),
150 has_padding: false,
151 report_count: u5::new(2),
152 packet_type: 203,
153 length_field: 2,
154 };
155
156 let mut buf = BitCursor::new(BitVec::<u8, Msb0>::from_vec(vec![1, 2, 3, 4]));
158 let result = read_rtcp_bye(&mut buf, rtcp_header);
159 assert!(result.is_err());
160 }
161
162 #[test]
163 fn test_bad_utf8_reason() {
164 let rtcp_header = RtcpHeader {
165 version: u2::new(2),
166 has_padding: false,
167 report_count: u5::new(2),
168 packet_type: 203,
169 length_field: 2,
170 };
171 #[rustfmt::skip]
172 let payload = vec![
173 0x00, 0x00, 0x00, 0x01,
175 0x00, 0x00, 0x00, 0x02,
177 0x02, 0xFF, 0xFF
179 ];
180 let mut buf = BitCursor::new(BitVec::<u8, Msb0>::from_vec(payload));
181 let result = read_rtcp_bye(&mut buf, rtcp_header);
182 assert!(result.is_err());
183 }
184}