blob: e3d7bd992033121b2eecb779f72f4dd7fb1df245 [file] [log] [blame]
// 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.
#include "cast/streaming/sender_report_builder.h"
#include "cast/streaming/packet_util.h"
#include "util/osp_logging.h"
namespace openscreen {
namespace cast {
SenderReportBuilder::SenderReportBuilder(RtcpSession* session)
: session_(session) {
OSP_DCHECK(session_);
}
SenderReportBuilder::~SenderReportBuilder() = default;
std::pair<absl::Span<uint8_t>, StatusReportId> SenderReportBuilder::BuildPacket(
const RtcpSenderReport& sender_report,
absl::Span<uint8_t> buffer) const {
OSP_CHECK_GE(buffer.size(), kRequiredBufferSize);
uint8_t* const packet_begin = buffer.data();
RtcpCommonHeader header;
header.packet_type = RtcpPacketType::kSenderReport;
header.payload_size = kRtcpSenderReportSize;
if (sender_report.report_block) {
header.with.report_count = 1;
header.payload_size += kRtcpReportBlockSize;
} else {
header.with.report_count = 0;
}
header.AppendFields(&buffer);
AppendField<uint32_t>(session_->sender_ssrc(), &buffer);
const NtpTimestamp ntp_timestamp =
session_->ntp_converter().ToNtpTimestamp(sender_report.reference_time);
AppendField<uint64_t>(ntp_timestamp, &buffer);
AppendField<uint32_t>(sender_report.rtp_timestamp.lower_32_bits(), &buffer);
AppendField<uint32_t>(sender_report.send_packet_count, &buffer);
AppendField<uint32_t>(sender_report.send_octet_count, &buffer);
if (sender_report.report_block) {
sender_report.report_block->AppendFields(&buffer);
}
uint8_t* const packet_end = buffer.data();
return std::make_pair(
absl::Span<uint8_t>(packet_begin, packet_end - packet_begin),
ToStatusReportId(ntp_timestamp));
}
Clock::time_point SenderReportBuilder::GetRecentReportTime(
StatusReportId report_id,
Clock::time_point on_or_before) const {
// Assumption: The |report_id| is the middle 32 bits of a 64-bit NtpTimestamp.
static_assert(ToStatusReportId(NtpTimestamp{0x0192a3b4c5d6e7f8}) ==
StatusReportId{0xa3b4c5d6},
"FIXME: ToStatusReportId() implementation changed.");
// Compute the maximum possible NtpTimestamp. Then, use its uppermost 16 bits
// and the 32 bits from the report_id to produce a reconstructed NtpTimestamp.
const NtpTimestamp max_timestamp =
session_->ntp_converter().ToNtpTimestamp(on_or_before);
// max_timestamp: HH......
// report_id: LLLL
// ↓↓ ↙↙↙↙
// reconstructed: HHLLLL00
NtpTimestamp reconstructed = (max_timestamp & (uint64_t{0xffff} << 48)) |
(static_cast<uint64_t>(report_id) << 16);
// If the reconstructed timestamp is greater than the maximum one, rollover
// of the lower 48 bits occurred. Subtract one from the upper 16 bits to
// rectify that.
if (reconstructed > max_timestamp) {
reconstructed -= uint64_t{1} << 48;
}
return session_->ntp_converter().ToLocalTime(reconstructed);
}
} // namespace cast
} // namespace openscreen