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