blob: 5f9db875560431931cf2bcd2b9e531bc53e253db [file] [log] [blame]
// 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