• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_parser.h"
6 
7 #include "cast/streaming/packet_util.h"
8 #include "util/osp_logging.h"
9 
10 namespace openscreen {
11 namespace cast {
12 
13 SenderReportParser::SenderReportWithId::SenderReportWithId() = default;
14 SenderReportParser::SenderReportWithId::~SenderReportWithId() = default;
15 
SenderReportParser(RtcpSession * session)16 SenderReportParser::SenderReportParser(RtcpSession* session)
17     : session_(session) {
18   OSP_DCHECK(session_);
19 }
20 
21 SenderReportParser::~SenderReportParser() = default;
22 
23 absl::optional<SenderReportParser::SenderReportWithId>
Parse(absl::Span<const uint8_t> buffer)24 SenderReportParser::Parse(absl::Span<const uint8_t> buffer) {
25   absl::optional<SenderReportWithId> sender_report;
26 
27   // The data contained in |buffer| can be a "compound packet," which means that
28   // it can be the concatenation of multiple RTCP packets. The loop here
29   // processes each one-by-one.
30   while (!buffer.empty()) {
31     const auto header = RtcpCommonHeader::Parse(buffer);
32     if (!header) {
33       return absl::nullopt;
34     }
35     buffer.remove_prefix(kRtcpCommonHeaderSize);
36     if (static_cast<int>(buffer.size()) < header->payload_size) {
37       return absl::nullopt;
38     }
39     auto chunk = buffer.subspan(0, header->payload_size);
40     buffer.remove_prefix(header->payload_size);
41 
42     // Only process Sender Reports with a matching SSRC.
43     if (header->packet_type != RtcpPacketType::kSenderReport) {
44       continue;
45     }
46     if (header->payload_size < kRtcpSenderReportSize) {
47       return absl::nullopt;
48     }
49     if (ConsumeField<uint32_t>(&chunk) != session_->sender_ssrc()) {
50       continue;
51     }
52     SenderReportWithId& report = sender_report.emplace();
53     const NtpTimestamp ntp_timestamp = ConsumeField<uint64_t>(&chunk);
54     report.report_id = ToStatusReportId(ntp_timestamp);
55     report.reference_time =
56         session_->ntp_converter().ToLocalTime(ntp_timestamp);
57     report.rtp_timestamp =
58         last_parsed_rtp_timestamp_.Expand(ConsumeField<uint32_t>(&chunk));
59     report.send_packet_count = ConsumeField<uint32_t>(&chunk);
60     report.send_octet_count = ConsumeField<uint32_t>(&chunk);
61     report.report_block = RtcpReportBlock::ParseOne(
62         chunk, header->with.report_count, session_->receiver_ssrc());
63   }
64 
65   // At this point, the packet is known to be well-formed. Cache the
66   // most-recently parsed RTP timestamp value for bit-expansion in future
67   // parses.
68   if (sender_report) {
69     last_parsed_rtp_timestamp_ = sender_report->rtp_timestamp;
70   }
71   return sender_report;
72 }
73 
74 }  // namespace cast
75 }  // namespace openscreen
76