You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
3.0 KiB
85 lines
3.0 KiB
// 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
|