1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/streaming/rtcp_common.h"
6
7 #include <algorithm>
8 #include <limits>
9
10 #include "cast/streaming/packet_util.h"
11 #include "util/saturate_cast.h"
12
13 namespace openscreen {
14 namespace cast {
15
16 RtcpCommonHeader::RtcpCommonHeader() = default;
17 RtcpCommonHeader::~RtcpCommonHeader() = default;
18
AppendFields(absl::Span<uint8_t> * buffer) const19 void RtcpCommonHeader::AppendFields(absl::Span<uint8_t>* buffer) const {
20 OSP_CHECK_GE(buffer->size(), kRtcpCommonHeaderSize);
21
22 uint8_t byte0 = kRtcpRequiredVersionAndPaddingBits
23 << kRtcpReportCountFieldNumBits;
24 switch (packet_type) {
25 case RtcpPacketType::kSenderReport:
26 case RtcpPacketType::kReceiverReport:
27 OSP_DCHECK_LE(with.report_count,
28 FieldBitmask<int>(kRtcpReportCountFieldNumBits));
29 byte0 |= with.report_count;
30 break;
31 case RtcpPacketType::kSourceDescription:
32 OSP_UNIMPLEMENTED();
33 break;
34 case RtcpPacketType::kApplicationDefined:
35 case RtcpPacketType::kPayloadSpecific:
36 switch (with.subtype) {
37 case RtcpSubtype::kPictureLossIndicator:
38 case RtcpSubtype::kFeedback:
39 byte0 |= static_cast<uint8_t>(with.subtype);
40 break;
41 case RtcpSubtype::kReceiverLog:
42 OSP_UNIMPLEMENTED();
43 break;
44 default:
45 OSP_NOTREACHED();
46 break;
47 }
48 break;
49 case RtcpPacketType::kExtendedReports:
50 break;
51 case RtcpPacketType::kNull:
52 OSP_NOTREACHED();
53 break;
54 }
55 AppendField<uint8_t>(byte0, buffer);
56
57 AppendField<uint8_t>(static_cast<uint8_t>(packet_type), buffer);
58
59 // The size of the packet must be evenly divisible by the 32-bit word size.
60 OSP_DCHECK_EQ(0, payload_size % sizeof(uint32_t));
61 AppendField<uint16_t>(payload_size / sizeof(uint32_t), buffer);
62 }
63
64 // static
Parse(absl::Span<const uint8_t> buffer)65 absl::optional<RtcpCommonHeader> RtcpCommonHeader::Parse(
66 absl::Span<const uint8_t> buffer) {
67 if (buffer.size() < kRtcpCommonHeaderSize) {
68 return absl::nullopt;
69 }
70
71 const uint8_t byte0 = ConsumeField<uint8_t>(&buffer);
72 if ((byte0 >> kRtcpReportCountFieldNumBits) !=
73 kRtcpRequiredVersionAndPaddingBits) {
74 return absl::nullopt;
75 }
76 const uint8_t report_count_or_subtype =
77 byte0 & FieldBitmask<uint8_t>(kRtcpReportCountFieldNumBits);
78
79 const uint8_t byte1 = ConsumeField<uint8_t>(&buffer);
80 if (!IsRtcpPacketType(byte1)) {
81 return absl::nullopt;
82 }
83
84 // Optionally set |header.with.report_count| or |header.with.subtype|,
85 // depending on the packet type.
86 RtcpCommonHeader header;
87 header.packet_type = static_cast<RtcpPacketType>(byte1);
88 switch (header.packet_type) {
89 case RtcpPacketType::kSenderReport:
90 case RtcpPacketType::kReceiverReport:
91 header.with.report_count = report_count_or_subtype;
92 break;
93 case RtcpPacketType::kApplicationDefined:
94 case RtcpPacketType::kPayloadSpecific:
95 switch (static_cast<RtcpSubtype>(report_count_or_subtype)) {
96 case RtcpSubtype::kPictureLossIndicator:
97 case RtcpSubtype::kReceiverLog:
98 case RtcpSubtype::kFeedback:
99 header.with.subtype =
100 static_cast<RtcpSubtype>(report_count_or_subtype);
101 break;
102 default: // Unknown subtype.
103 header.with.subtype = RtcpSubtype::kNull;
104 break;
105 }
106 break;
107 default:
108 // Neither |header.with.report_count| nor |header.with.subtype| are used.
109 break;
110 }
111
112 header.payload_size =
113 static_cast<int>(ConsumeField<uint16_t>(&buffer)) * sizeof(uint32_t);
114
115 return header;
116 }
117
118 RtcpReportBlock::RtcpReportBlock() = default;
119 RtcpReportBlock::~RtcpReportBlock() = default;
120
AppendFields(absl::Span<uint8_t> * buffer) const121 void RtcpReportBlock::AppendFields(absl::Span<uint8_t>* buffer) const {
122 OSP_CHECK_GE(buffer->size(), kRtcpReportBlockSize);
123
124 AppendField<uint32_t>(ssrc, buffer);
125 OSP_DCHECK_GE(packet_fraction_lost_numerator,
126 std::numeric_limits<uint8_t>::min());
127 OSP_DCHECK_LE(packet_fraction_lost_numerator,
128 std::numeric_limits<uint8_t>::max());
129 OSP_DCHECK_GE(cumulative_packets_lost, 0);
130 OSP_DCHECK_LE(cumulative_packets_lost,
131 FieldBitmask<int>(kRtcpCumulativePacketsFieldNumBits));
132 AppendField<uint32_t>(
133 (static_cast<int>(packet_fraction_lost_numerator)
134 << kRtcpCumulativePacketsFieldNumBits) |
135 (static_cast<int>(cumulative_packets_lost) &
136 FieldBitmask<uint32_t>(kRtcpCumulativePacketsFieldNumBits)),
137 buffer);
138 AppendField<uint32_t>(extended_high_sequence_number, buffer);
139 const int64_t jitter_ticks = jitter / RtpTimeDelta::FromTicks(1);
140 OSP_DCHECK_GE(jitter_ticks, 0);
141 OSP_DCHECK_LE(jitter_ticks, int64_t{std::numeric_limits<uint32_t>::max()});
142 AppendField<uint32_t>(jitter_ticks, buffer);
143 AppendField<uint32_t>(last_status_report_id, buffer);
144 const int64_t delay_ticks = delay_since_last_report.count();
145 OSP_DCHECK_GE(delay_ticks, 0);
146 OSP_DCHECK_LE(delay_ticks, int64_t{std::numeric_limits<uint32_t>::max()});
147 AppendField<uint32_t>(delay_ticks, buffer);
148 }
149
SetPacketFractionLostNumerator(int64_t num_apparently_sent,int64_t num_received)150 void RtcpReportBlock::SetPacketFractionLostNumerator(
151 int64_t num_apparently_sent,
152 int64_t num_received) {
153 if (num_apparently_sent <= 0) {
154 packet_fraction_lost_numerator = 0;
155 return;
156 }
157 // The following computes the fraction of packets lost as "one minus
158 // |num_received| divided by |num_apparently_sent|" and scales by 256 (the
159 // kPacketFractionLostDenominator). It's valid for |num_received| to be
160 // greater than |num_apparently_sent| in some cases (e.g., if duplicate
161 // packets were received from the network).
162 const int64_t numerator =
163 ((num_apparently_sent - num_received) * kPacketFractionLostDenominator) /
164 num_apparently_sent;
165 // Since the value must be in the range [0,255], just do a saturate_cast
166 // to the uint8_t type to clamp.
167 packet_fraction_lost_numerator = saturate_cast<uint8_t>(numerator);
168 }
169
SetCumulativePacketsLost(int64_t num_apparently_sent,int64_t num_received)170 void RtcpReportBlock::SetCumulativePacketsLost(int64_t num_apparently_sent,
171 int64_t num_received) {
172 const int64_t num_lost = num_apparently_sent - num_received;
173 // Clamp to valid range supported by the wire format (and RTP spec).
174 //
175 // Note that |num_lost| can be negative if duplicate packets were received.
176 // The RFC spec (https://tools.ietf.org/html/rfc3550#section-6.4.1) states
177 // this should result in a clamped, "zero loss" value.
178 cumulative_packets_lost = static_cast<int>(
179 std::min(std::max<int64_t>(num_lost, 0),
180 FieldBitmask<int64_t>(kRtcpCumulativePacketsFieldNumBits)));
181 }
182
SetDelaySinceLastReport(Clock::duration local_clock_delay)183 void RtcpReportBlock::SetDelaySinceLastReport(
184 Clock::duration local_clock_delay) {
185 // Clamp to valid range supported by the wire format (and RTP spec). The
186 // bounds checking is done in terms of Clock::duration, since doing the checks
187 // after the duration_cast may allow overflow to occur in the duration_cast
188 // math (well, only for unusually large inputs).
189 constexpr Delay kMaxValidReportedDelay{std::numeric_limits<uint32_t>::max()};
190 constexpr auto kMaxValidLocalClockDelay =
191 Clock::to_duration(kMaxValidReportedDelay);
192 if (local_clock_delay > kMaxValidLocalClockDelay) {
193 delay_since_last_report = kMaxValidReportedDelay;
194 return;
195 }
196 if (local_clock_delay <= Clock::duration::zero()) {
197 delay_since_last_report = Delay::zero();
198 return;
199 }
200
201 // If this point is reached, then the |local_clock_delay| is representable as
202 // a Delay within the valid range.
203 delay_since_last_report =
204 std::chrono::duration_cast<Delay>(local_clock_delay);
205 }
206
207 // static
ParseOne(absl::Span<const uint8_t> buffer,int report_count,Ssrc ssrc)208 absl::optional<RtcpReportBlock> RtcpReportBlock::ParseOne(
209 absl::Span<const uint8_t> buffer,
210 int report_count,
211 Ssrc ssrc) {
212 if (static_cast<int>(buffer.size()) < (kRtcpReportBlockSize * report_count)) {
213 return absl::nullopt;
214 }
215
216 absl::optional<RtcpReportBlock> result;
217 for (int block = 0; block < report_count; ++block) {
218 if (ConsumeField<uint32_t>(&buffer) != ssrc) {
219 // Skip-over report block meant for some other recipient.
220 buffer.remove_prefix(kRtcpReportBlockSize - sizeof(uint32_t));
221 continue;
222 }
223
224 RtcpReportBlock& report_block = result.emplace();
225 report_block.ssrc = ssrc;
226 const auto second_word = ConsumeField<uint32_t>(&buffer);
227 report_block.packet_fraction_lost_numerator =
228 second_word >> kRtcpCumulativePacketsFieldNumBits;
229 report_block.cumulative_packets_lost =
230 second_word &
231 FieldBitmask<uint32_t>(kRtcpCumulativePacketsFieldNumBits);
232 report_block.extended_high_sequence_number =
233 ConsumeField<uint32_t>(&buffer);
234 report_block.jitter =
235 RtpTimeDelta::FromTicks(ConsumeField<uint32_t>(&buffer));
236 report_block.last_status_report_id = ConsumeField<uint32_t>(&buffer);
237 report_block.delay_since_last_report =
238 RtcpReportBlock::Delay(ConsumeField<uint32_t>(&buffer));
239 }
240 return result;
241 }
242
243 RtcpSenderReport::RtcpSenderReport() = default;
244 RtcpSenderReport::~RtcpSenderReport() = default;
245
246 } // namespace cast
247 } // namespace openscreen
248