Chromium Code Reviews| Index: webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc |
| diff --git a/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ddaffc47801a53bd139c01d0c965c0424df9b9eb |
| --- /dev/null |
| +++ b/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc |
| @@ -0,0 +1,305 @@ |
| +/* |
| + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| + * |
| + * Use of this source code is governed by a BSD-style license |
| + * that can be found in the LICENSE file in the root of the source |
| + * tree. An additional intellectual property rights grant can be found |
| + * in the file PATENTS. All contributing project authors may |
| + * be found in the AUTHORS file in the root of the source tree. |
| + */ |
| + |
| +#include <vector> |
| + |
| +#include "webrtc/config.h" |
| +#include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h" |
| +#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" |
| +#include "webrtc/modules/rtp_rtcp/source/fec_test_helper.h" |
| +#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" |
| +#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" |
| +#include "webrtc/system_wrappers/include/clock.h" |
| +#include "webrtc/test/gtest.h" |
| + |
| +namespace webrtc { |
| + |
| +namespace { |
| + |
| +using test::fec::AugmentedPacket; |
| +using test::fec::AugmentedPacketGenerator; |
| + |
| +constexpr int kFlexfecPayloadType = 123; |
| +constexpr uint32_t kMediaSsrc = 1234; |
| +constexpr uint32_t kFlexfecSsrc = 5678; |
| +const std::vector<RtpExtension> kNoRtpHeaderExtensions; |
| +// Assume a single protected media SSRC. |
| +constexpr size_t kFlexfecMaxHeaderSize = 32; |
| +constexpr size_t kPayloadLength = 50; |
| + |
| +constexpr int64_t kInitialSimulatedClockTime = 1; |
| +// These values are deterministically given by the PRNG, due to our fixed seed. |
| +// They should be updated if the PRNG implementation changes. |
| +constexpr uint16_t kDeterministicSequenceNumber = 17590; |
| +constexpr uint32_t kDeterministicTimestamp = 3016887581; |
| + |
| +std::unique_ptr<RtpPacketToSend> GenerateSingleFlexfecPacket( |
| + FlexfecSender* sender) { |
| + // Parameters selected to generate a single FEC packet. |
| + constexpr size_t kNumPackets = 4; |
| + FecProtectionParams params = {15, 3, kFecMaskRandom}; |
| + |
| + sender->SetFecParameters(¶ms); |
| + AugmentedPacketGenerator packet_generator(kMediaSsrc); |
| + packet_generator.NewFrame(kNumPackets); |
| + for (size_t i = 0; i < kNumPackets; ++i) { |
| + std::unique_ptr<AugmentedPacket> packet = |
| + packet_generator.NextPacket(i, kPayloadLength); |
| + RtpPacketToSend rtp_packet(nullptr); // No header extensions. |
| + rtp_packet.Parse(packet->data, packet->length); |
| + EXPECT_EQ(0, sender->AddRtpPacketAndGenerateFec(&rtp_packet)); |
| + } |
| + EXPECT_TRUE(sender->FecAvailable()); |
| + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = |
| + sender->GetFecPackets(); |
| + EXPECT_FALSE(sender->FecAvailable()); |
| + EXPECT_EQ(1U, fec_packets.size()); |
| + |
| + return std::move(fec_packets.front()); |
| +} |
| + |
| +} // namespace |
| + |
| +TEST(FlexfecSenderTest, NoFecAvailableBeforeMediaAdded) { |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kNoRtpHeaderExtensions, &clock); |
| + |
| + EXPECT_FALSE(sender->FecAvailable()); |
| + auto fec_packets = sender->GetFecPackets(); |
| + EXPECT_EQ(0U, fec_packets.size()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, ProtectOneFrameWithOneFecPacket) { |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kNoRtpHeaderExtensions, &clock); |
| + auto fec_packet = GenerateSingleFlexfecPacket(sender.get()); |
| + |
| + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); |
| + EXPECT_FALSE(fec_packet->Marker()); |
| + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); |
| + EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber()); |
| + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); |
| + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); |
| + EXPECT_GE(fec_packet->payload_size(), kPayloadLength); |
|
danilchap
2016/10/20 15:12:58
constant 1st for EXPECT macros (i.e.
EXPECT_LE(kPa
brandtr
2016/10/24 12:52:08
Done.
|
| +} |
| + |
| +TEST(FlexfecSenderTest, ProtectTwoFramesWithOneFecPacket) { |
| + // Parameters selected to generate a single FEC packet per frame. |
| + constexpr size_t kNumFrames = 2; |
| + constexpr size_t kNumPacketsPerFrame = 2; |
| + FecProtectionParams params = {15, 3, kFecMaskRandom}; |
|
danilchap
2016/10/20 15:12:58
Are values 15 and 3 important?
If they are, may be
brandtr
2016/10/24 12:52:08
Yes, they are important. Clarified according to yo
|
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kNoRtpHeaderExtensions, &clock); |
| + sender->SetFecParameters(¶ms); |
| + |
| + AugmentedPacketGenerator packet_generator(kMediaSsrc); |
| + for (size_t i = 0; i < kNumFrames; ++i) { |
| + packet_generator.NewFrame(kNumPacketsPerFrame); |
| + for (size_t j = 0; j < kNumPacketsPerFrame; ++j) { |
| + std::unique_ptr<AugmentedPacket> packet = |
| + packet_generator.NextPacket(i, kPayloadLength); |
| + RtpPacketToSend rtp_packet(nullptr); |
| + rtp_packet.Parse(packet->data, packet->length); |
| + EXPECT_EQ(0, sender->AddRtpPacketAndGenerateFec(&rtp_packet)); |
| + } |
| + } |
| + EXPECT_TRUE(sender->FecAvailable()); |
| + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = |
| + sender->GetFecPackets(); |
| + EXPECT_FALSE(sender->FecAvailable()); |
| + EXPECT_EQ(1U, fec_packets.size()); |
| + |
| + RtpPacketToSend* fec_packet = fec_packets.front().get(); |
| + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); |
| + EXPECT_FALSE(fec_packet->Marker()); |
| + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); |
| + EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber()); |
| + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); |
| + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, ProtectTwoFramesWithTwoFecPackets) { |
| + // Parameters selected to generate a single FEC packet per frame. |
| + constexpr size_t kNumFrames = 2; |
| + constexpr size_t kNumPacketsPerFrame = 4; |
| + FecProtectionParams params = {15, 3, kFecMaskRandom}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kNoRtpHeaderExtensions, &clock); |
| + sender->SetFecParameters(¶ms); |
| + |
| + AugmentedPacketGenerator packet_generator(kMediaSsrc); |
| + for (size_t i = 0; i < kNumFrames; ++i) { |
| + packet_generator.NewFrame(kNumPacketsPerFrame); |
| + for (size_t j = 0; j < kNumPacketsPerFrame; ++j) { |
| + std::unique_ptr<AugmentedPacket> packet = |
| + packet_generator.NextPacket(i, kPayloadLength); |
| + RtpPacketToSend rtp_packet(nullptr); |
| + rtp_packet.Parse(packet->data, packet->length); |
| + EXPECT_EQ(0, sender->AddRtpPacketAndGenerateFec(&rtp_packet)); |
| + } |
| + EXPECT_TRUE(sender->FecAvailable()); |
| + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = |
| + sender->GetFecPackets(); |
| + EXPECT_FALSE(sender->FecAvailable()); |
| + EXPECT_EQ(1U, fec_packets.size()); |
| + |
| + RtpPacketToSend* fec_packet = fec_packets.front().get(); |
| + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); |
| + EXPECT_FALSE(fec_packet->Marker()); |
| + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); |
| + EXPECT_EQ(static_cast<uint16_t>(kDeterministicSequenceNumber + i), |
| + fec_packet->SequenceNumber()); |
| + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); |
| + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); |
| + } |
| +} |
| + |
| +// In the tests, we only consider RTP header extensions that are useful for BWE. |
| +TEST(FlexfecSenderTest, NoRtpHeaderExtensionsForBweByDefault) { |
| + const std::vector<RtpExtension> kRtpHeaderExtensions{}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kRtpHeaderExtensions, &clock); |
| + auto fec_packet = GenerateSingleFlexfecPacket(sender.get()); |
| + |
| + EXPECT_FALSE(fec_packet->ReserveExtension<AbsoluteSendTime>()); |
| + EXPECT_FALSE(fec_packet->ReserveExtension<TransmissionOffset>()); |
| + EXPECT_FALSE(fec_packet->ReserveExtension<TransportSequenceNumber>()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) { |
| + const std::vector<RtpExtension> kRtpHeaderExtensions{ |
| + {RtpExtension::kAbsSendTimeUri, 1}}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kRtpHeaderExtensions, &clock); |
| + auto fec_packet = GenerateSingleFlexfecPacket(sender.get()); |
| + |
| + EXPECT_TRUE(fec_packet->ReserveExtension<AbsoluteSendTime>()); |
|
danilchap
2016/10/20 15:12:58
may be fec_packet->HasExtension<AbsoluteSendTime>(
brandtr
2016/10/24 12:52:08
Of course! Fixed.
|
| + EXPECT_FALSE(fec_packet->ReserveExtension<TransmissionOffset>()); |
| + EXPECT_FALSE(fec_packet->ReserveExtension<TransportSequenceNumber>()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) { |
| + const std::vector<RtpExtension> kRtpHeaderExtensions{ |
| + {RtpExtension::kTimestampOffsetUri, 1}}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kRtpHeaderExtensions, &clock); |
| + auto fec_packet = GenerateSingleFlexfecPacket(sender.get()); |
| + |
| + EXPECT_FALSE(fec_packet->ReserveExtension<AbsoluteSendTime>()); |
| + EXPECT_TRUE(fec_packet->ReserveExtension<TransmissionOffset>()); |
| + EXPECT_FALSE(fec_packet->ReserveExtension<TransportSequenceNumber>()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) { |
| + const std::vector<RtpExtension> kRtpHeaderExtensions{ |
| + {RtpExtension::kTransportSequenceNumberUri, 1}}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kRtpHeaderExtensions, &clock); |
| + auto fec_packet = GenerateSingleFlexfecPacket(sender.get()); |
| + |
| + EXPECT_FALSE(fec_packet->ReserveExtension<AbsoluteSendTime>()); |
| + EXPECT_FALSE(fec_packet->ReserveExtension<TransmissionOffset>()); |
| + EXPECT_TRUE(fec_packet->ReserveExtension<TransportSequenceNumber>()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) { |
| + const std::vector<RtpExtension> kRtpHeaderExtensions{ |
| + {RtpExtension::kAbsSendTimeUri, 1}, |
| + {RtpExtension::kTimestampOffsetUri, 2}, |
| + {RtpExtension::kTransportSequenceNumberUri, 3}}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kRtpHeaderExtensions, &clock); |
| + auto fec_packet = GenerateSingleFlexfecPacket(sender.get()); |
| + |
| + EXPECT_TRUE(fec_packet->ReserveExtension<AbsoluteSendTime>()); |
| + EXPECT_TRUE(fec_packet->ReserveExtension<TransmissionOffset>()); |
| + EXPECT_TRUE(fec_packet->ReserveExtension<TransportSequenceNumber>()); |
| +} |
| + |
| +TEST(FlexfecSenderTest, MaxPacketOverhead) { |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, |
| + kNoRtpHeaderExtensions, &clock); |
| + |
| + EXPECT_EQ(kFlexfecMaxHeaderSize, sender->MaxPacketOverhead()); |
| +} |
| + |
| +// TODO(brandtr): Remove this test when we support multistream protection. |
| +TEST(FlexfecSenderTest, DoesNotProtectMultipleMediaStreams) { |
| + // Parameters selected to generate a single FEC packet. |
| + constexpr size_t kNumPacketsStream1 = 4; |
| + constexpr size_t kNumPacketsStream2 = 4; |
| + constexpr uint32_t kMediaSsrcStream1 = kMediaSsrc; |
| + constexpr uint32_t kMediaSsrcStream2 = kMediaSsrc + 1; |
| + FecProtectionParams params = {15, 3, kFecMaskRandom}; |
| + SimulatedClock clock(kInitialSimulatedClockTime); |
| + std::unique_ptr<FlexfecSender> sender = |
| + FlexfecSender::Create(kFlexfecPayloadType, kFlexfecSsrc, |
| + kMediaSsrcStream2, kNoRtpHeaderExtensions, &clock); |
| + sender->SetFecParameters(¶ms); |
| + |
| + // Feed FlexfecSender media packets from stream 1, which IS NOT protected. |
| + AugmentedPacketGenerator packet_generator1(kMediaSsrcStream1); |
| + packet_generator1.NewFrame(kNumPacketsStream1); |
| + for (size_t i = 0; i < kNumPacketsStream1; ++i) { |
| + std::unique_ptr<AugmentedPacket> packet = |
| + packet_generator1.NextPacket(i, kPayloadLength); |
| + RtpPacketToSend rtp_packet(nullptr); |
| + rtp_packet.Parse(packet->data, packet->length); |
| + EXPECT_EQ(0, sender->AddRtpPacketAndGenerateFec(&rtp_packet)); |
| + } |
| + EXPECT_FALSE(sender->FecAvailable()); |
| + |
| + // Feed FlexfecSender media packets from stream 2, which IS protected. |
| + AugmentedPacketGenerator packet_generator2(kMediaSsrcStream2); |
| + packet_generator2.NewFrame(kNumPacketsStream2); |
| + for (size_t i = 0; i < kNumPacketsStream2; ++i) { |
| + std::unique_ptr<AugmentedPacket> packet = |
| + packet_generator2.NextPacket(i, kPayloadLength); |
| + RtpPacketToSend rtp_packet(nullptr); |
| + rtp_packet.Parse(packet->data, packet->length); |
| + EXPECT_EQ(0, sender->AddRtpPacketAndGenerateFec(&rtp_packet)); |
| + } |
| + EXPECT_TRUE(sender->FecAvailable()); |
| + std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets = |
| + sender->GetFecPackets(); |
| + EXPECT_FALSE(sender->FecAvailable()); |
| + EXPECT_EQ(1U, fec_packets.size()); |
| + |
| + RtpPacketToSend* fec_packet = fec_packets.front().get(); |
| + EXPECT_EQ(kRtpHeaderSize, fec_packet->headers_size()); |
| + EXPECT_FALSE(fec_packet->Marker()); |
| + EXPECT_EQ(kFlexfecPayloadType, fec_packet->PayloadType()); |
| + EXPECT_EQ(kDeterministicSequenceNumber, fec_packet->SequenceNumber()); |
| + EXPECT_EQ(kDeterministicTimestamp, fec_packet->Timestamp()); |
| + EXPECT_EQ(kFlexfecSsrc, fec_packet->Ssrc()); |
| + EXPECT_GE(fec_packet->payload_size(), kPayloadLength); |
| +} |
| + |
| +} // namespace webrtc |