// 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_parser.h" #include "cast/streaming/packet_util.h" #include "util/osp_logging.h" namespace openscreen { namespace cast { SenderReportParser::SenderReportWithId::SenderReportWithId() = default; SenderReportParser::SenderReportWithId::~SenderReportWithId() = default; SenderReportParser::SenderReportParser(RtcpSession* session) : session_(session) { OSP_DCHECK(session_); } SenderReportParser::~SenderReportParser() = default; absl::optional SenderReportParser::Parse(absl::Span buffer) { absl::optional sender_report; // The data contained in |buffer| can be a "compound packet," which means that // it can be the concatenation of multiple RTCP packets. The loop here // processes each one-by-one. while (!buffer.empty()) { const auto header = RtcpCommonHeader::Parse(buffer); if (!header) { return absl::nullopt; } buffer.remove_prefix(kRtcpCommonHeaderSize); if (static_cast(buffer.size()) < header->payload_size) { return absl::nullopt; } auto chunk = buffer.subspan(0, header->payload_size); buffer.remove_prefix(header->payload_size); // Only process Sender Reports with a matching SSRC. if (header->packet_type != RtcpPacketType::kSenderReport) { continue; } if (header->payload_size < kRtcpSenderReportSize) { return absl::nullopt; } if (ConsumeField(&chunk) != session_->sender_ssrc()) { continue; } SenderReportWithId& report = sender_report.emplace(); const NtpTimestamp ntp_timestamp = ConsumeField(&chunk); report.report_id = ToStatusReportId(ntp_timestamp); report.reference_time = session_->ntp_converter().ToLocalTime(ntp_timestamp); report.rtp_timestamp = last_parsed_rtp_timestamp_.Expand(ConsumeField(&chunk)); report.send_packet_count = ConsumeField(&chunk); report.send_octet_count = ConsumeField(&chunk); report.report_block = RtcpReportBlock::ParseOne( chunk, header->with.report_count, session_->receiver_ssrc()); } // At this point, the packet is known to be well-formed. Cache the // most-recently parsed RTP timestamp value for bit-expansion in future // parses. if (sender_report) { last_parsed_rtp_timestamp_ = sender_report->rtp_timestamp; } return sender_report; } } // namespace cast } // namespace openscreen