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 #ifndef CAST_STREAMING_RTCP_COMMON_H_
6 #define CAST_STREAMING_RTCP_COMMON_H_
7 
8 #include <stdint.h>
9 
10 #include <tuple>
11 #include <vector>
12 
13 #include "absl/types/optional.h"
14 #include "absl/types/span.h"
15 #include "cast/streaming/frame_id.h"
16 #include "cast/streaming/ntp_time.h"
17 #include "cast/streaming/rtp_defines.h"
18 #include "cast/streaming/rtp_time.h"
19 #include "cast/streaming/ssrc.h"
20 
21 namespace openscreen {
22 namespace cast {
23 
24 struct RtcpCommonHeader {
25   RtcpCommonHeader();
26   ~RtcpCommonHeader();
27 
28   RtcpPacketType packet_type = RtcpPacketType::kNull;
29 
30   union {
31     // The number of report blocks if |packet_type| is kSenderReport or
32     // kReceiverReport.
33     int report_count;
34 
35     // Indicates the type of an application-defined message if |packet_type| is
36     // kApplicationDefined or kPayloadSpecific.
37     RtcpSubtype subtype;
38 
39     // Otherwise, not used.
40   } with{0};
41 
42   // The size (in bytes) of the RTCP packet, not including the header.
43   int payload_size = 0;
44 
45   // Serializes this header into the first |kRtcpCommonHeaderSize| bytes of the
46   // given |buffer| and adjusts |buffer| to point to the first byte after it.
47   void AppendFields(absl::Span<uint8_t>* buffer) const;
48 
49   // Parse from the 4-byte wire format in |buffer|. Returns nullopt if the data
50   // is corrupt.
51   static absl::optional<RtcpCommonHeader> Parse(
52       absl::Span<const uint8_t> buffer);
53 };
54 
55 // The middle 32-bits of the 64-bit NtpTimestamp field from the Sender Reports.
56 // This is used as an opaque identifier that the Receiver will use in its
57 // reports to refer to specific previous Sender Reports.
58 using StatusReportId = uint32_t;
ToStatusReportId(NtpTimestamp ntp_timestamp)59 constexpr StatusReportId ToStatusReportId(NtpTimestamp ntp_timestamp) {
60   return static_cast<uint32_t>(ntp_timestamp >> 16);
61 }
62 
63 // One of these is optionally included with a Sender Report or a Receiver
64 // Report. See: https://tools.ietf.org/html/rfc3550#section-6.4.1
65 struct RtcpReportBlock {
66   RtcpReportBlock();
67   ~RtcpReportBlock();
68 
69   // The intended recipient of this report block.
70   Ssrc ssrc = 0;
71 
72   // The fraction of RTP packets lost since the last report, specified as a
73   // variable numerator and fixed denominator. The numerator will always be in
74   // the range [0,255] since, semantically:
75   //
76   //   a. Negative values are impossible.
77   //   b. Values greater than 255 would indicate 100% packet loss, and so a
78   //      report block would not be generated in the first place.
79   int packet_fraction_lost_numerator = 0;
80   static constexpr int kPacketFractionLostDenominator = 256;
81 
82   // The total number of RTP packets lost since the start of the session. This
83   // value will always be in the range [0,2^24-1], as the wire format only
84   // provides 24 bits; so, wrap-around is possible.
85   int cumulative_packets_lost = 0;
86 
87   // The highest sequence number received in any RTP packet. Wrap-around is
88   // possible.
89   uint32_t extended_high_sequence_number = 0;
90 
91   // An estimate of the recent variance in RTP packet arrival times.
92   RtpTimeDelta jitter;
93 
94   // The last Status Report received.
95   StatusReportId last_status_report_id{};
96 
97   // The delay between when the peer received the most-recent Status Report and
98   // when this report was sent. The timebase is 65536 ticks per second and,
99   // because of the wire format, this value will always be in the range
100   // [0,65536) seconds.
101   using Delay = std::chrono::duration<int64_t, std::ratio<1, 65536>>;
102   Delay delay_since_last_report{};
103 
104   // Convenience helper to compute/assign the |packet_fraction_lost_numerator|,
105   // based on the |num_apparently_sent| and |num_received| packet counts since
106   // the last report was sent.
107   void SetPacketFractionLostNumerator(int64_t num_apparently_sent,
108                                       int64_t num_received);
109 
110   // Convenience helper to compute/assign the |cumulative_packets_lost|, based
111   // on the |num_apparently_sent| and |num_received| packet counts since the
112   // start of the entire session.
113   void SetCumulativePacketsLost(int64_t num_apparently_sent,
114                                 int64_t num_received);
115 
116   // Convenience helper to convert the given |local_clock_delay| to the
117   // RtcpReportBlock::Delay timebase, then clamp and assign it to
118   // |delay_since_last_report|.
119   void SetDelaySinceLastReport(Clock::duration local_clock_delay);
120 
121   // Serializes this report block in the first |kRtcpReportBlockSize| bytes of
122   // the given |buffer| and adjusts |buffer| to point to the first byte after
123   // it.
124   void AppendFields(absl::Span<uint8_t>* buffer) const;
125 
126   // Scans the wire-format report blocks in |buffer|, searching for one with the
127   // matching |ssrc| and, if found, returns the parse result. Returns nullopt if
128   // the data is corrupt or no report block with the matching SSRC was found.
129   static absl::optional<RtcpReportBlock>
130   ParseOne(absl::Span<const uint8_t> buffer, int report_count, Ssrc ssrc);
131 };
132 
133 struct RtcpSenderReport {
134   RtcpSenderReport();
135   ~RtcpSenderReport();
136 
137   // The point-in-time at which this report was sent, according to both: 1) the
138   // common reference clock shared by all RTP streams; 2) the RTP timestamp on
139   // the media capture/playout timeline. Together, these are used by a Receiver
140   // to achieve A/V synchronization across RTP streams for playout.
141   Clock::time_point reference_time{};
142   RtpTimeTicks rtp_timestamp;
143 
144   // The total number of RTP packets transmitted since the start of the session
145   // (wrap-around is possible).
146   uint32_t send_packet_count = 0;
147 
148   // The total number of payload bytes transmitted in RTP packets since the
149   // start of the session (wrap-around is possible).
150   uint32_t send_octet_count = 0;
151 
152   // The report block, if present. While the RTCP spec allows for zero or
153   // multiple reports, Cast Streaming only uses zero or one.
154   absl::optional<RtcpReportBlock> report_block;
155 };
156 
157 // A pair of IDs that refers to a specific missing packet within a frame. If
158 // |packet_id| is kAllPacketsLost, then it represents all the packets of a
159 // frame.
160 struct PacketNack {
161   FrameId frame_id;
162   FramePacketId packet_id;
163 
164   // Comparison operators. Define more when you need them!
165   // TODO(miu): In C++20, just
166   // replace all of this with one operator<=>() definition to get them all for
167   // free.
168   constexpr bool operator==(const PacketNack& other) const {
169     return frame_id == other.frame_id && packet_id == other.packet_id;
170   }
171   constexpr bool operator!=(const PacketNack& other) const {
172     return frame_id != other.frame_id || packet_id != other.packet_id;
173   }
174   constexpr bool operator<(const PacketNack& other) const {
175     return (frame_id < other.frame_id) ||
176            (frame_id == other.frame_id && packet_id < other.packet_id);
177   }
178 };
179 
180 }  // namespace cast
181 }  // namespace openscreen
182 
183 #endif  // CAST_STREAMING_RTCP_COMMON_H_
184