| // 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/rtp_packet_parser.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "cast/streaming/packet_util.h" |
| #include "util/osp_logging.h" |
| |
| namespace openscreen { |
| namespace cast { |
| |
| RtpPacketParser::RtpPacketParser(Ssrc sender_ssrc) |
| : sender_ssrc_(sender_ssrc), highest_rtp_frame_id_(FrameId::first()) {} |
| |
| RtpPacketParser::~RtpPacketParser() = default; |
| |
| absl::optional<RtpPacketParser::ParseResult> RtpPacketParser::Parse( |
| absl::Span<const uint8_t> buffer) { |
| if (buffer.size() < kRtpPacketMinValidSize || |
| ConsumeField<uint8_t>(&buffer) != kRtpRequiredFirstByte) { |
| return absl::nullopt; |
| } |
| |
| // RTP header elements. |
| // |
| // Note: M (marker bit) is ignored here. Technically, according to the Cast |
| // Streaming spec, it should only be set when PID == Max PID; but, let's be |
| // lenient just in case some sender implementations don't adhere to this tiny, |
| // subtle detail. |
| const uint8_t payload_type = |
| ConsumeField<uint8_t>(&buffer) & kRtpPayloadTypeMask; |
| if (!IsRtpPayloadType(payload_type)) { |
| return absl::nullopt; |
| } |
| ParseResult result; |
| result.payload_type = static_cast<RtpPayloadType>(payload_type); |
| result.sequence_number = ConsumeField<uint16_t>(&buffer); |
| result.rtp_timestamp = |
| last_parsed_rtp_timestamp_.Expand(ConsumeField<uint32_t>(&buffer)); |
| if (ConsumeField<uint32_t>(&buffer) != sender_ssrc_) { |
| return absl::nullopt; |
| } |
| |
| // Cast-specific header elements. |
| const uint8_t byte12 = ConsumeField<uint8_t>(&buffer); |
| result.is_key_frame = !!(byte12 & kRtpKeyFrameBitMask); |
| const bool has_referenced_frame_id = |
| !!(byte12 & kRtpHasReferenceFrameIdBitMask); |
| const size_t num_cast_extensions = byte12 & kRtpExtensionCountMask; |
| result.frame_id = |
| highest_rtp_frame_id_.Expand(ConsumeField<uint8_t>(&buffer)); |
| result.packet_id = ConsumeField<uint16_t>(&buffer); |
| result.max_packet_id = ConsumeField<uint16_t>(&buffer); |
| if (result.max_packet_id == kAllPacketsLost) { |
| return absl::nullopt; // Packet ID cannot be the special value. |
| } |
| if (result.packet_id > result.max_packet_id) { |
| return absl::nullopt; |
| } |
| if (has_referenced_frame_id) { |
| if (buffer.empty()) { |
| return absl::nullopt; |
| } |
| result.referenced_frame_id = |
| result.frame_id.Expand(ConsumeField<uint8_t>(&buffer)); |
| } else { |
| // By default, if no reference frame ID was provided, the assumption is that |
| // a key frame only references itself, while non-key frames reference only |
| // their immediate predecessor. |
| result.referenced_frame_id = |
| result.is_key_frame ? result.frame_id : (result.frame_id - 1); |
| } |
| |
| // Zero or more Cast extensions. |
| for (size_t i = 0; i < num_cast_extensions; ++i) { |
| if (buffer.size() < sizeof(uint16_t)) { |
| return absl::nullopt; |
| } |
| const uint16_t type_and_size = ConsumeField<uint16_t>(&buffer); |
| const uint8_t type = type_and_size >> kNumExtensionDataSizeFieldBits; |
| const size_t size = |
| type_and_size & FieldBitmask<uint16_t>(kNumExtensionDataSizeFieldBits); |
| if (buffer.size() < size) { |
| return absl::nullopt; |
| } |
| if (type == kAdaptiveLatencyRtpExtensionType) { |
| if (size != sizeof(uint16_t)) { |
| return absl::nullopt; |
| } |
| result.new_playout_delay = |
| std::chrono::milliseconds(ReadBigEndian<uint16_t>(buffer.data())); |
| } |
| buffer.remove_prefix(size); |
| } |
| |
| // All remaining data in the packet is the payload. |
| result.payload = buffer; |
| |
| // At this point, the packet is known to be well-formed. Track recent field |
| // values for later parses, to bit-extend the truncated values found in future |
| // packets. |
| last_parsed_rtp_timestamp_ = result.rtp_timestamp; |
| highest_rtp_frame_id_ = std::max(highest_rtp_frame_id_, result.frame_id); |
| |
| return result; |
| } |
| |
| RtpPacketParser::ParseResult::ParseResult() = default; |
| RtpPacketParser::ParseResult::~ParseResult() = default; |
| |
| } // namespace cast |
| } // namespace openscreen |