xref: /webrtc/rtcp/src/header.rs (revision 259fddd2)
1 use std::fmt;
2 use std::io::{Read, Write};
3 
4 use util::Error;
5 
6 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
7 
8 use super::errors::*;
9 
10 #[cfg(test)]
11 mod header_test;
12 
13 // PacketType specifies the type of an RTCP packet
14 // RTCP packet types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4
15 
16 #[derive(Debug, Copy, Clone, PartialEq)]
17 pub enum PacketType {
18     Unsupported = 0,
19     SenderReport = 200,              // RFC 3550, 6.4.1
20     ReceiverReport = 201,            // RFC 3550, 6.4.2
21     SourceDescription = 202,         // RFC 3550, 6.5
22     Goodbye = 203,                   // RFC 3550, 6.6
23     ApplicationDefined = 204,        // RFC 3550, 6.7 (unimplemented)
24     TransportSpecificFeedback = 205, // RFC 4585, 6051
25     PayloadSpecificFeedback = 206,   // RFC 4585, 6.3
26 }
27 
28 impl Default for PacketType {
29     fn default() -> Self {
30         PacketType::Unsupported
31     }
32 }
33 
34 // Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
35 pub const FORMAT_SLI: u8 = 2;
36 pub const FORMAT_PLI: u8 = 1;
37 pub const FORMAT_FIR: u8 = 4;
38 pub const FORMAT_TLN: u8 = 1;
39 pub const FORMAT_RRR: u8 = 5;
40 pub const FORMAT_REMB: u8 = 15;
41 //https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
42 pub const FORMAT_TCC: u8 = 15;
43 
44 impl fmt::Display for PacketType {
45     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46         let s = match self {
47             PacketType::Unsupported => "Unsupported",
48             PacketType::SenderReport => "SR",
49             PacketType::ReceiverReport => "RR",
50             PacketType::SourceDescription => "SDES",
51             PacketType::Goodbye => "BYE",
52             PacketType::ApplicationDefined => "APP",
53             PacketType::TransportSpecificFeedback => "TSFB",
54             PacketType::PayloadSpecificFeedback => "PSFB",
55         };
56         write!(f, "{}", s)
57     }
58 }
59 
60 impl From<u8> for PacketType {
61     fn from(b: u8) -> Self {
62         match b {
63             200 => PacketType::SenderReport,              // RFC 3550, 6.4.1
64             201 => PacketType::ReceiverReport,            // RFC 3550, 6.4.2
65             202 => PacketType::SourceDescription,         // RFC 3550, 6.5
66             203 => PacketType::Goodbye,                   // RFC 3550, 6.6
67             204 => PacketType::ApplicationDefined,        // RFC 3550, 6.7 (unimplemented)
68             205 => PacketType::TransportSpecificFeedback, // RFC 4585, 6051
69             206 => PacketType::PayloadSpecificFeedback,   // RFC 4585, 6.3
70             _ => PacketType::Unsupported,
71         }
72     }
73 }
74 
75 const RTP_VERSION: u8 = 2;
76 
77 // A Header is the common header shared by all RTCP packets
78 #[derive(Debug, PartialEq, Default, Clone)]
79 pub struct Header {
80     // If the padding bit is set, this individual RTCP packet contains
81     // some additional padding octets at the end which are not part of
82     // the control information but are included in the length field.
83     pub padding: bool,
84     // The number of reception reports, sources contained or FMT in this packet (depending on the Type)
85     pub count: u8,
86     // The RTCP packet type for this packet
87     pub packet_type: PacketType,
88     // The length of this RTCP packet in 32-bit words minus one,
89     // including the header and any padding.
90     pub length: u16,
91 }
92 
93 const VERSION_SHIFT: u8 = 6;
94 const VERSION_MASK: u8 = 0x3;
95 const PADDING_SHIFT: u8 = 5;
96 const PADDING_MASK: u8 = 0x1;
97 const COUNT_SHIFT: u8 = 0;
98 const COUNT_MASK: u8 = 0x1f;
99 
100 pub const HEADER_LENGTH: usize = 4;
101 pub const COUNT_MAX: usize = (1 << 5) - 1;
102 pub const SSRC_LENGTH: usize = 4;
103 pub const SDES_MAX_OCTET_COUNT: usize = (1 << 8) - 1;
104 
105 // Marshal encodes the Header in binary
106 impl Header {
107     pub fn marshal<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
108         /*
109          *  0                   1                   2                   3
110          *  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
111          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112          * |V=2|P|    RC   |   PT=SR=200   |             length            |
113          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114          */
115 
116         let mut b0 = RTP_VERSION << VERSION_SHIFT;
117 
118         if self.padding {
119             b0 |= 1 << PADDING_SHIFT
120         }
121 
122         if self.count > 31 {
123             return Err(ERR_INVALID_HEADER.clone());
124         }
125         b0 |= self.count << COUNT_SHIFT;
126         writer.write_u8(b0)?;
127 
128         let b1 = self.packet_type as u8;
129         writer.write_u8(b1)?;
130 
131         writer.write_u16::<BigEndian>(self.length)?;
132 
133         Ok(())
134     }
135 
136     // Unmarshal decodes the Header from binary
137     pub fn unmarshal<R: Read>(reader: &mut R) -> Result<Self, Error> {
138         /*
139          *  0                   1                   2                   3
140          *  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
141          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
142          * |V=2|P|    RC   |      PT       |             length            |
143          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
144          */
145         let b0 = reader.read_u8()?;
146         let version = b0 >> VERSION_SHIFT & VERSION_MASK;
147         if version != RTP_VERSION {
148             return Err(ERR_BAD_VERSION.clone());
149         }
150 
151         let padding = (b0 >> PADDING_SHIFT & PADDING_MASK) > 0;
152         let count = b0 >> COUNT_SHIFT & COUNT_MASK;
153 
154         let b1 = reader.read_u8()?;
155         let packet_type: PacketType = b1.into();
156         if packet_type == PacketType::Unsupported {
157             return Err(ERR_WRONG_TYPE.clone());
158         }
159 
160         let length = reader.read_u16::<BigEndian>()?;
161 
162         Ok(Header {
163             padding,
164             // The number of reception reports, sources contained or FMT in this packet (depending on the Type)
165             count,
166             // The RTCP packet type for this packet
167             packet_type,
168             // The length of this RTCP packet in 32-bit words minus one,
169             // including the header and any padding.
170             length,
171         })
172     }
173 }
174