// 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, StatusReportId> SenderReportBuilder::BuildPacket( const RtcpSenderReport& sender_report, absl::Span 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(session_->sender_ssrc(), &buffer); const NtpTimestamp ntp_timestamp = session_->ntp_converter().ToNtpTimestamp(sender_report.reference_time); AppendField(ntp_timestamp, &buffer); AppendField(sender_report.rtp_timestamp.lower_32_bits(), &buffer); AppendField(sender_report.send_packet_count, &buffer); AppendField(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(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(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