// Copyright 2019 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CAST_STREAMING_RTCP_COMMON_H_ #define CAST_STREAMING_RTCP_COMMON_H_ #include #include #include #include "absl/types/optional.h" #include "absl/types/span.h" #include "cast/streaming/frame_id.h" #include "cast/streaming/ntp_time.h" #include "cast/streaming/rtp_defines.h" #include "cast/streaming/rtp_time.h" #include "cast/streaming/ssrc.h" namespace openscreen { namespace cast { struct RtcpCommonHeader { RtcpCommonHeader(); ~RtcpCommonHeader(); RtcpPacketType packet_type = RtcpPacketType::kNull; union { // The number of report blocks if |packet_type| is kSenderReport or // kReceiverReport. int report_count; // Indicates the type of an application-defined message if |packet_type| is // kApplicationDefined or kPayloadSpecific. RtcpSubtype subtype; // Otherwise, not used. } with{0}; // The size (in bytes) of the RTCP packet, not including the header. int payload_size = 0; // Serializes this header into the first |kRtcpCommonHeaderSize| bytes of the // given |buffer| and adjusts |buffer| to point to the first byte after it. void AppendFields(absl::Span* buffer) const; // Parse from the 4-byte wire format in |buffer|. Returns nullopt if the data // is corrupt. static absl::optional Parse( absl::Span buffer); }; // The middle 32-bits of the 64-bit NtpTimestamp field from the Sender Reports. // This is used as an opaque identifier that the Receiver will use in its // reports to refer to specific previous Sender Reports. using StatusReportId = uint32_t; constexpr StatusReportId ToStatusReportId(NtpTimestamp ntp_timestamp) { return static_cast(ntp_timestamp >> 16); } // One of these is optionally included with a Sender Report or a Receiver // Report. See: https://tools.ietf.org/html/rfc3550#section-6.4.1 struct RtcpReportBlock { RtcpReportBlock(); ~RtcpReportBlock(); // The intended recipient of this report block. Ssrc ssrc = 0; // The fraction of RTP packets lost since the last report, specified as a // variable numerator and fixed denominator. The numerator will always be in // the range [0,255] since, semantically: // // a. Negative values are impossible. // b. Values greater than 255 would indicate 100% packet loss, and so a // report block would not be generated in the first place. int packet_fraction_lost_numerator = 0; static constexpr int kPacketFractionLostDenominator = 256; // The total number of RTP packets lost since the start of the session. This // value will always be in the range [0,2^24-1], as the wire format only // provides 24 bits; so, wrap-around is possible. int cumulative_packets_lost = 0; // The highest sequence number received in any RTP packet. Wrap-around is // possible. uint32_t extended_high_sequence_number = 0; // An estimate of the recent variance in RTP packet arrival times. RtpTimeDelta jitter; // The last Status Report received. StatusReportId last_status_report_id{}; // The delay between when the peer received the most-recent Status Report and // when this report was sent. The timebase is 65536 ticks per second and, // because of the wire format, this value will always be in the range // [0,65536) seconds. using Delay = std::chrono::duration>; Delay delay_since_last_report{}; // Convenience helper to compute/assign the |packet_fraction_lost_numerator|, // based on the |num_apparently_sent| and |num_received| packet counts since // the last report was sent. void SetPacketFractionLostNumerator(int64_t num_apparently_sent, int64_t num_received); // Convenience helper to compute/assign the |cumulative_packets_lost|, based // on the |num_apparently_sent| and |num_received| packet counts since the // start of the entire session. void SetCumulativePacketsLost(int64_t num_apparently_sent, int64_t num_received); // Convenience helper to convert the given |local_clock_delay| to the // RtcpReportBlock::Delay timebase, then clamp and assign it to // |delay_since_last_report|. void SetDelaySinceLastReport(Clock::duration local_clock_delay); // Serializes this report block in the first |kRtcpReportBlockSize| bytes of // the given |buffer| and adjusts |buffer| to point to the first byte after // it. void AppendFields(absl::Span* buffer) const; // Scans the wire-format report blocks in |buffer|, searching for one with the // matching |ssrc| and, if found, returns the parse result. Returns nullopt if // the data is corrupt or no report block with the matching SSRC was found. static absl::optional ParseOne(absl::Span buffer, int report_count, Ssrc ssrc); }; struct RtcpSenderReport { RtcpSenderReport(); ~RtcpSenderReport(); // The point-in-time at which this report was sent, according to both: 1) the // common reference clock shared by all RTP streams; 2) the RTP timestamp on // the media capture/playout timeline. Together, these are used by a Receiver // to achieve A/V synchronization across RTP streams for playout. Clock::time_point reference_time{}; RtpTimeTicks rtp_timestamp; // The total number of RTP packets transmitted since the start of the session // (wrap-around is possible). uint32_t send_packet_count = 0; // The total number of payload bytes transmitted in RTP packets since the // start of the session (wrap-around is possible). uint32_t send_octet_count = 0; // The report block, if present. While the RTCP spec allows for zero or // multiple reports, Cast Streaming only uses zero or one. absl::optional report_block; }; // A pair of IDs that refers to a specific missing packet within a frame. If // |packet_id| is kAllPacketsLost, then it represents all the packets of a // frame. struct PacketNack { FrameId frame_id; FramePacketId packet_id; // Comparison operators. Define more when you need them! // TODO(miu): In C++20, just // replace all of this with one operator<=>() definition to get them all for // free. constexpr bool operator==(const PacketNack& other) const { return frame_id == other.frame_id && packet_id == other.packet_id; } constexpr bool operator!=(const PacketNack& other) const { return frame_id != other.frame_id || packet_id != other.packet_id; } constexpr bool operator<(const PacketNack& other) const { return (frame_id < other.frame_id) || (frame_id == other.frame_id && packet_id < other.packet_id); } }; } // namespace cast } // namespace openscreen #endif // CAST_STREAMING_RTCP_COMMON_H_