311 lines
12 KiB
C++
311 lines
12 KiB
C++
// 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 "cast/streaming/rtp_defines.h"
|
|
#include "gtest/gtest.h"
|
|
#include "util/big_endian.h"
|
|
|
|
namespace openscreen {
|
|
namespace cast {
|
|
namespace {
|
|
|
|
// Tests that a simple packet for a key frame can be parsed.
|
|
TEST(RtpPacketParserTest, ParsesPacketForKeyFrame) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xbe, 0xef, // Sequence number.
|
|
9, 8, 7, 6, // RTP timestamp.
|
|
1, 2, 3, 4, // SSRC.
|
|
0b10000000, // Is key frame, no extensions.
|
|
5, // Frame ID.
|
|
0xa, 0xb, // Packet ID.
|
|
0xa, 0xc, // Max packet ID.
|
|
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x01020304;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
const auto result = parser.Parse(kInput);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(RtpPayloadType::kAudioOpus, result->payload_type);
|
|
EXPECT_EQ(UINT16_C(0xbeef), result->sequence_number);
|
|
EXPECT_EQ(RtpTimeTicks() + RtpTimeDelta::FromTicks(0x09080706),
|
|
result->rtp_timestamp);
|
|
EXPECT_TRUE(result->is_key_frame);
|
|
EXPECT_EQ(FrameId::first() + 5, result->frame_id);
|
|
EXPECT_EQ(FramePacketId{0x0a0b}, result->packet_id);
|
|
EXPECT_EQ(FramePacketId{0x0a0c}, result->max_packet_id);
|
|
EXPECT_EQ(FrameId::first() + 5, result->referenced_frame_id);
|
|
EXPECT_EQ(0, result->new_playout_delay.count());
|
|
const absl::Span<const uint8_t> expected_payload(kInput + 18, 8);
|
|
ASSERT_EQ(expected_payload, result->payload);
|
|
EXPECT_TRUE(expected_payload == result->payload);
|
|
}
|
|
|
|
// Tests that a packet which includes a "referenced frame ID" can be parsed.
|
|
TEST(RtpPacketParserTest, ParsesPacketForNonKeyFrameWithReferenceFrameId) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xde, 0xad, // Sequence number.
|
|
2, 4, 6, 8, // RTP timestamp.
|
|
0, 0, 1, 1, // SSRC.
|
|
0b01000000, // Not a key frame, but has ref frame ID; no extensions.
|
|
42, // Frame ID.
|
|
0x0, 0xb, // Packet ID.
|
|
0x0, 0xc, // Max packet ID.
|
|
39, // Reference Frame ID.
|
|
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29 // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x00000101;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
const auto result = parser.Parse(kInput);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(RtpPayloadType::kAudioOpus, result->payload_type);
|
|
EXPECT_EQ(UINT16_C(0xdead), result->sequence_number);
|
|
EXPECT_EQ(RtpTimeTicks() + RtpTimeDelta::FromTicks(0x02040608),
|
|
result->rtp_timestamp);
|
|
EXPECT_FALSE(result->is_key_frame);
|
|
EXPECT_EQ(FrameId::first() + 42, result->frame_id);
|
|
EXPECT_EQ(FramePacketId{0x000b}, result->packet_id);
|
|
EXPECT_EQ(FramePacketId{0x000c}, result->max_packet_id);
|
|
EXPECT_EQ(FrameId::first() + 39, result->referenced_frame_id);
|
|
EXPECT_EQ(0, result->new_playout_delay.count());
|
|
const absl::Span<const uint8_t> expected_payload(kInput + 19, 15);
|
|
ASSERT_EQ(expected_payload, result->payload);
|
|
EXPECT_TRUE(expected_payload == result->payload);
|
|
}
|
|
|
|
// Tests that a packet which lacks a "referenced frame ID" field can be parsed,
|
|
// but the parser will provide the implied referenced_frame_id value in the
|
|
// result.
|
|
TEST(RtpPacketParserTest, ParsesPacketForNonKeyFrameWithoutReferenceFrameId) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xde, 0xad, // Sequence number.
|
|
2, 4, 6, 8, // RTP timestamp.
|
|
0, 0, 1, 1, // SSRC.
|
|
0b00000000, // Not a key frame, no ref frame ID; no extensions.
|
|
42, // Frame ID.
|
|
0x0, 0xb, // Packet ID.
|
|
0x0, 0xc, // Max packet ID.
|
|
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29 // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x00000101;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
const auto result = parser.Parse(kInput);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(RtpPayloadType::kAudioOpus, result->payload_type);
|
|
EXPECT_EQ(UINT16_C(0xdead), result->sequence_number);
|
|
EXPECT_EQ(RtpTimeTicks() + RtpTimeDelta::FromTicks(0x02040608),
|
|
result->rtp_timestamp);
|
|
EXPECT_FALSE(result->is_key_frame);
|
|
EXPECT_EQ(FrameId::first() + 42, result->frame_id);
|
|
EXPECT_EQ(FramePacketId{0x000b}, result->packet_id);
|
|
EXPECT_EQ(FramePacketId{0x000c}, result->max_packet_id);
|
|
EXPECT_EQ(FrameId::first() + 41, result->referenced_frame_id);
|
|
EXPECT_EQ(0, result->new_playout_delay.count());
|
|
const absl::Span<const uint8_t> expected_payload(kInput + 18, 15);
|
|
ASSERT_EQ(expected_payload, result->payload);
|
|
EXPECT_TRUE(expected_payload == result->payload);
|
|
}
|
|
|
|
// Tests that a packet indicating a new playout delay can be parsed.
|
|
TEST(RtpPacketParserTest, ParsesPacketWithAdaptiveLatencyExtension) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xde, 0xad, // Sequence number.
|
|
2, 4, 6, 8, // RTP timestamp.
|
|
0, 0, 1, 1, // SSRC.
|
|
0b11000001, // Is key frame, has ref frame ID; has one extension.
|
|
64, // Frame ID.
|
|
0x0, 0x0, // Packet ID.
|
|
0x0, 0xc, // Max packet ID.
|
|
64, // Reference Frame ID.
|
|
4, 2, 1, 14, // Cast Adaptive Latency Extension data.
|
|
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29 // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x00000101;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
const auto result = parser.Parse(kInput);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(RtpPayloadType::kAudioOpus, result->payload_type);
|
|
EXPECT_EQ(UINT16_C(0xdead), result->sequence_number);
|
|
EXPECT_EQ(RtpTimeTicks() + RtpTimeDelta::FromTicks(0x02040608),
|
|
result->rtp_timestamp);
|
|
EXPECT_TRUE(result->is_key_frame);
|
|
EXPECT_EQ(FrameId::first() + 64, result->frame_id);
|
|
EXPECT_EQ(FramePacketId{0x0000}, result->packet_id);
|
|
EXPECT_EQ(FramePacketId{0x000c}, result->max_packet_id);
|
|
EXPECT_EQ(FrameId::first() + 64, result->referenced_frame_id);
|
|
EXPECT_EQ(270, result->new_playout_delay.count());
|
|
const absl::Span<const uint8_t> expected_payload(kInput + 23, 15);
|
|
ASSERT_EQ(expected_payload, result->payload);
|
|
EXPECT_TRUE(expected_payload == result->payload);
|
|
}
|
|
|
|
// Tests that the parser can handle multiple Cast Header Extensions in a RTP
|
|
// packet, and ignores all but the one (Adaptive Latency) that it understands.
|
|
TEST(RtpPacketParserTest, ParsesPacketWithMultipleExtensions) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xde, 0xad, // Sequence number.
|
|
2, 4, 6, 8, // RTP timestamp.
|
|
0, 0, 1, 1, // SSRC.
|
|
0b11000011, // Is key frame, has ref frame ID; has 3 extensions.
|
|
64, // Frame ID.
|
|
0x0, 0xb, // Packet ID.
|
|
0x0, 0xc, // Max packet ID.
|
|
64, // Reference Frame ID.
|
|
8, 2, 0, 0, // Unknown extension with 2 bytes of data.
|
|
4, 2, 1, 14, // Cast Adaptive Latency Extension data.
|
|
16, 5, 0, 0, 0, 0, 0, // Unknown extension with 5 bytes of data.
|
|
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29 // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x00000101;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
const auto result = parser.Parse(kInput);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(RtpPayloadType::kAudioOpus, result->payload_type);
|
|
EXPECT_EQ(UINT16_C(0xdead), result->sequence_number);
|
|
EXPECT_EQ(RtpTimeTicks() + RtpTimeDelta::FromTicks(0x02040608),
|
|
result->rtp_timestamp);
|
|
EXPECT_TRUE(result->is_key_frame);
|
|
EXPECT_EQ(FrameId::first() + 64, result->frame_id);
|
|
EXPECT_EQ(FramePacketId{0x000b}, result->packet_id);
|
|
EXPECT_EQ(FramePacketId{0x000c}, result->max_packet_id);
|
|
EXPECT_EQ(FrameId::first() + 64, result->referenced_frame_id);
|
|
EXPECT_EQ(270, result->new_playout_delay.count());
|
|
const absl::Span<const uint8_t> expected_payload(kInput + 34, 15);
|
|
ASSERT_EQ(expected_payload, result->payload);
|
|
EXPECT_TRUE(expected_payload == result->payload);
|
|
}
|
|
|
|
// Tests that the parser ignores packets from an unknown source.
|
|
TEST(RtpPacketParserTest, IgnoresPacketWithWrongSsrc) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xbe, 0xef, // Sequence number.
|
|
9, 8, 7, 6, // RTP timestamp.
|
|
4, 3, 2, 1, // SSRC.
|
|
0b10000000, // Is key frame, no extensions.
|
|
5, // Frame ID.
|
|
0xa, 0xb, // Packet ID.
|
|
0xa, 0xc, // Max packet ID.
|
|
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x01020304;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
const auto result = parser.Parse(kInput);
|
|
ASSERT_FALSE(result);
|
|
}
|
|
|
|
// Tests that unexpected truncations in the RTP packets does not crash the
|
|
// parser, and that it correctly errors-out.
|
|
TEST(RtpPacketParserTest, RejectsTruncatedPackets) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xde, 0xad, // Sequence number.
|
|
2, 4, 6, 8, // RTP timestamp.
|
|
0, 0, 1, 1, // SSRC.
|
|
0b11000011, // Is key frame, has ref frame ID; has 3 extensions.
|
|
64, // Frame ID.
|
|
0x0, 0xb, // Packet ID.
|
|
0x0, 0xc, // Max packet ID.
|
|
64, // Reference Frame ID.
|
|
8, 2, 0, 0, // Unknown extension with 2 bytes of data.
|
|
4, 2, 1, 14, // Cast Adaptive Latency Extension data.
|
|
16, 5, 0, 0, 0, 0, 0, // Unknown extension with 5 bytes of data.
|
|
1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29 // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x00000101;
|
|
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
ASSERT_FALSE(parser.Parse(absl::Span<const uint8_t>(kInput, 1)));
|
|
ASSERT_FALSE(parser.Parse(absl::Span<const uint8_t>(kInput, 18)));
|
|
ASSERT_FALSE(parser.Parse(absl::Span<const uint8_t>(kInput, 22)));
|
|
ASSERT_FALSE(parser.Parse(absl::Span<const uint8_t>(kInput, 33)));
|
|
|
|
// When truncated to 34 bytes, the parser should see it as a packet with zero
|
|
// payload bytes.
|
|
const auto result_without_payload =
|
|
parser.Parse(absl::Span<const uint8_t>(kInput, 34));
|
|
ASSERT_TRUE(result_without_payload);
|
|
EXPECT_TRUE(result_without_payload->payload.empty());
|
|
|
|
// And, of course, with the entire kInput available, the parser should see it
|
|
// as a packet with 15 bytes of payload.
|
|
const auto result_with_payload =
|
|
parser.Parse(absl::Span<const uint8_t>(kInput, sizeof(kInput)));
|
|
ASSERT_TRUE(result_with_payload);
|
|
EXPECT_EQ(size_t{15}, result_with_payload->payload.size());
|
|
}
|
|
|
|
// Tests that the parser rejects invalid packet ID values.
|
|
TEST(RtpPacketParserTest, RejectsPacketWithBadFramePacketIds) {
|
|
// clang-format off
|
|
const uint8_t kInput[] = {
|
|
0b10000000, // Version/Padding byte.
|
|
96, // Payload type byte.
|
|
0xbe, 0xef, // Sequence number.
|
|
9, 8, 7, 6, // RTP timestamp.
|
|
1, 2, 3, 4, // SSRC.
|
|
0b10000000, // Is key frame, no extensions.
|
|
5, // Frame ID.
|
|
0xa, 0xb, // Packet ID (which is GREATER than the max packet ID).
|
|
0x0, 0x1, // Max packet ID.
|
|
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, // Payload.
|
|
};
|
|
// clang-format on
|
|
const Ssrc kSenderSsrc = 0x01020304;
|
|
|
|
// The parser should reject the packet because its packet ID field is greater
|
|
// than the max packet ID.
|
|
RtpPacketParser parser(kSenderSsrc);
|
|
ASSERT_FALSE(parser.Parse(kInput));
|
|
|
|
// Now, modify the packet such that its "max packet ID" field is set to the
|
|
// special "all packets lost" value. This makes the "packet ID" field valid,
|
|
// because it is less than the "max packet ID", but the "max packet ID" value
|
|
// itself is invalid.
|
|
uint8_t input_with_bad_max_packet_id[sizeof(kInput)];
|
|
memcpy(input_with_bad_max_packet_id, kInput, sizeof(kInput));
|
|
WriteBigEndian<uint16_t>(kAllPacketsLost, &input_with_bad_max_packet_id[16]);
|
|
const uint16_t packet_id =
|
|
ReadBigEndian<uint16_t>(&input_with_bad_max_packet_id[14]);
|
|
ASSERT_LE(packet_id, kAllPacketsLost);
|
|
ASSERT_FALSE(parser.Parse(input_with_bad_max_packet_id));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace cast
|
|
} // namespace openscreen
|