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/sender_report_builder.h"
6 
7 #include "cast/streaming/packet_util.h"
8 #include "util/logging.h"
9 
10 namespace openscreen {
11 namespace cast {
12 
SenderReportBuilder(RtcpSession * session)13 SenderReportBuilder::SenderReportBuilder(RtcpSession* session)
14     : session_(session) {
15   OSP_DCHECK(session_);
16 }
17 
18 SenderReportBuilder::~SenderReportBuilder() = default;
19 
BuildPacket(const RtcpSenderReport & sender_report,absl::Span<uint8_t> buffer) const20 std::pair<absl::Span<uint8_t>, StatusReportId> SenderReportBuilder::BuildPacket(
21     const RtcpSenderReport& sender_report,
22     absl::Span<uint8_t> buffer) const {
23   OSP_CHECK_GE(buffer.size(), kRequiredBufferSize);
24 
25   uint8_t* const packet_begin = buffer.data();
26 
27   RtcpCommonHeader header;
28   header.packet_type = RtcpPacketType::kSenderReport;
29   header.payload_size = kRtcpSenderReportSize;
30   if (sender_report.report_block) {
31     header.with.report_count = 1;
32     header.payload_size += kRtcpReportBlockSize;
33   } else {
34     header.with.report_count = 0;
35   }
36   header.AppendFields(&buffer);
37 
38   AppendField<uint32_t>(session_->sender_ssrc(), &buffer);
39   const NtpTimestamp ntp_timestamp =
40       session_->ntp_converter().ToNtpTimestamp(sender_report.reference_time);
41   AppendField<uint64_t>(ntp_timestamp, &buffer);
42   AppendField<uint32_t>(sender_report.rtp_timestamp.lower_32_bits(), &buffer);
43   AppendField<uint32_t>(sender_report.send_packet_count, &buffer);
44   AppendField<uint32_t>(sender_report.send_octet_count, &buffer);
45   if (sender_report.report_block) {
46     sender_report.report_block->AppendFields(&buffer);
47   }
48 
49   uint8_t* const packet_end = buffer.data();
50   return std::make_pair(
51       absl::Span<uint8_t>(packet_begin, packet_end - packet_begin),
52       ToStatusReportId(ntp_timestamp));
53 }
54 
GetRecentReportTime(StatusReportId report_id,Clock::time_point on_or_before) const55 Clock::time_point SenderReportBuilder::GetRecentReportTime(
56     StatusReportId report_id,
57     Clock::time_point on_or_before) const {
58   // Assumption: The |report_id| is the middle 32 bits of a 64-bit NtpTimestamp.
59   static_assert(ToStatusReportId(NtpTimestamp{0x0192a3b4c5d6e7f8}) ==
60                     StatusReportId{0xa3b4c5d6},
61                 "FIXME: ToStatusReportId() implementation changed.");
62 
63   // Compute the maximum possible NtpTimestamp. Then, use its uppermost 16 bits
64   // and the 32 bits from the report_id to produce a reconstructed NtpTimestamp.
65   const NtpTimestamp max_timestamp =
66       session_->ntp_converter().ToNtpTimestamp(on_or_before);
67   // max_timestamp: HH......
68   //     report_id:     LLLL
69   //                ↓↓ ↙↙↙↙
70   // reconstructed: HHLLLL00
71   NtpTimestamp reconstructed = (max_timestamp & (uint64_t{0xffff} << 48)) |
72                                (static_cast<uint64_t>(report_id) << 16);
73   //  If the reconstructed timestamp is greater than the maximum one, rollover
74   //  of the lower 48 bits occurred. Subtract one from the upper 16 bits to
75   //  rectify that.
76   if (reconstructed > max_timestamp) {
77     reconstructed -= uint64_t{1} << 48;
78   }
79 
80   return session_->ntp_converter().ToLocalTime(reconstructed);
81 }
82 
83 }  // namespace cast
84 }  // namespace openscreen
85