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/osp_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