blob: 3d46ee3be81eba467ad2e6a0c4f3476af8d1aaf3 [file] [log] [blame]
/*
* 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 "modules/rtp_rtcp/include/flexfec_sender.h"
#include <vector>
#include "api/environment/environment.h"
#include "api/environment/environment_factory.h"
#include "api/rtp_parameters.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/fec_test_helper.h"
#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/rtp_rtcp/source/rtp_sender.h"
#include "system_wrappers/include/clock.h"
#include "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 char kNoMid[] = "";
const std::vector<RtpExtension> kNoRtpHeaderExtensions;
const std::vector<RtpExtensionSize> kNoRtpHeaderExtensionSizes;
// 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 = 28732;
constexpr uint32_t kDeterministicTimestamp = 2305613085;
// Round up to the nearest size that is a multiple of 4.
size_t Word32Align(size_t size) {
uint32_t remainder = size % 4;
if (remainder != 0)
return size + 4 - remainder;
return size;
}
std::unique_ptr<RtpPacketToSend> GenerateSingleFlexfecPacket(
FlexfecSender* sender) {
// Parameters selected to generate a single FEC packet.
FecProtectionParams params;
params.fec_rate = 15;
params.max_fec_frames = 1;
params.fec_mask_type = kFecMaskRandom;
constexpr size_t kNumPackets = 4;
sender->SetProtectionParameters(params, params);
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);
sender->AddPacketAndGenerateFec(rtp_packet);
}
std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
sender->GetFecPackets();
EXPECT_EQ(1U, fec_packets.size());
EXPECT_TRUE(sender->GetFecPackets().empty());
return std::move(fec_packets.front());
}
} // namespace
TEST(FlexfecSenderTest, Ssrc) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, nullptr /* rtp_state */);
EXPECT_EQ(kFlexfecSsrc, sender.FecSsrc());
}
TEST(FlexfecSenderTest, NoFecAvailableBeforeMediaAdded) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, nullptr /* rtp_state */);
EXPECT_TRUE(sender.GetFecPackets().empty());
}
TEST(FlexfecSenderTest, ProtectOneFrameWithOneFecPacket) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
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_LE(kPayloadLength, fec_packet->payload_size());
}
TEST(FlexfecSenderTest, ProtectTwoFramesWithOneFecPacket) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
// FEC parameters selected to generate a single FEC packet per frame.
FecProtectionParams params;
params.fec_rate = 15;
params.max_fec_frames = 2;
params.fec_mask_type = kFecMaskRandom;
constexpr size_t kNumFrames = 2;
constexpr size_t kNumPacketsPerFrame = 2;
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, nullptr /* rtp_state */);
sender.SetProtectionParameters(params, params);
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);
sender.AddPacketAndGenerateFec(rtp_packet);
}
}
std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
sender.GetFecPackets();
ASSERT_EQ(1U, fec_packets.size());
EXPECT_TRUE(sender.GetFecPackets().empty());
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) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
// FEC parameters selected to generate a single FEC packet per frame.
FecProtectionParams params;
params.fec_rate = 30;
params.max_fec_frames = 1;
params.fec_mask_type = kFecMaskRandom;
constexpr size_t kNumFrames = 2;
constexpr size_t kNumPacketsPerFrame = 2;
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, nullptr /* rtp_state */);
sender.SetProtectionParameters(params, params);
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);
sender.AddPacketAndGenerateFec(rtp_packet);
}
std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
sender.GetFecPackets();
ASSERT_EQ(1U, fec_packets.size());
EXPECT_TRUE(sender.GetFecPackets().empty());
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) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{};
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
}
TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kAbsSendTimeUri, 1}};
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
}
TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kTimestampOffsetUri, 1}};
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
EXPECT_FALSE(fec_packet->HasExtension<TransportSequenceNumber>());
}
TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kTransportSequenceNumberUri, 1}};
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_FALSE(fec_packet->HasExtension<AbsoluteSendTime>());
EXPECT_FALSE(fec_packet->HasExtension<TransmissionOffset>());
EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
}
TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kAbsSendTimeUri, 1},
{RtpExtension::kTimestampOffsetUri, 2},
{RtpExtension::kTransportSequenceNumberUri, 3}};
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kRtpHeaderExtensions, kNoRtpHeaderExtensionSizes,
nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_TRUE(fec_packet->HasExtension<AbsoluteSendTime>());
EXPECT_TRUE(fec_packet->HasExtension<TransmissionOffset>());
EXPECT_TRUE(fec_packet->HasExtension<TransportSequenceNumber>());
}
TEST(FlexfecSenderTest, MaxPacketOverhead) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, nullptr /* rtp_state */);
EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead());
}
TEST(FlexfecSenderTest, MaxPacketOverheadWithExtensions) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kAbsSendTimeUri, 1},
{RtpExtension::kTimestampOffsetUri, 2},
{RtpExtension::kTransportSequenceNumberUri, 3}};
const size_t kExtensionHeaderLength = 1;
const size_t kRtpOneByteHeaderLength = 4;
const size_t kExtensionsTotalSize =
Word32Align(kRtpOneByteHeaderLength + kExtensionHeaderLength +
AbsoluteSendTime::kValueSizeBytes + kExtensionHeaderLength +
TransmissionOffset::kValueSizeBytes + kExtensionHeaderLength +
TransportSequenceNumber::kValueSizeBytes);
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kRtpHeaderExtensions,
RTPSender::FecExtensionSizes(), nullptr /* rtp_state */);
EXPECT_EQ(kExtensionsTotalSize + kFlexfecMaxHeaderSize,
sender.MaxPacketOverhead());
}
TEST(FlexfecSenderTest, MidIncludedInPacketsWhenSet) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kMidUri, 1}};
const char kMid[] = "mid";
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, kMid,
kRtpHeaderExtensions, RTPSender::FecExtensionSizes(),
nullptr /* rtp_state */);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
std::string mid;
ASSERT_TRUE(fec_packet->GetExtension<RtpMid>(&mid));
EXPECT_EQ(kMid, mid);
}
TEST(FlexfecSenderTest, SetsAndGetsRtpState) {
SimulatedClock clock(kInitialSimulatedClockTime);
const Environment env = CreateEnvironment(&clock);
RtpState initial_rtp_state;
initial_rtp_state.sequence_number = 100;
initial_rtp_state.start_timestamp = 200;
FlexfecSender sender(env, kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoMid, kNoRtpHeaderExtensions,
kNoRtpHeaderExtensionSizes, &initial_rtp_state);
auto fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_EQ(initial_rtp_state.sequence_number, fec_packet->SequenceNumber());
EXPECT_EQ(initial_rtp_state.start_timestamp, fec_packet->Timestamp());
clock.AdvanceTimeMilliseconds(1000);
fec_packet = GenerateSingleFlexfecPacket(&sender);
EXPECT_EQ(initial_rtp_state.sequence_number + 1,
fec_packet->SequenceNumber());
EXPECT_EQ(initial_rtp_state.start_timestamp + 1 * kVideoPayloadTypeFrequency,
fec_packet->Timestamp());
RtpState updated_rtp_state = sender.GetRtpState().value();
EXPECT_EQ(initial_rtp_state.sequence_number + 2,
updated_rtp_state.sequence_number);
EXPECT_EQ(initial_rtp_state.start_timestamp,
updated_rtp_state.start_timestamp);
}
} // namespace webrtc