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 |