Add FlexfecSender.

This class will interface RTPSenderVideo with the underlying
erasure code. It is functionally similar to ProducerFec
(to be renamed UlpfecGenerator). In fact, the FlexfecSender is a
friend of ProducerFec, and reuses most of its implementation.
Besides the fact that FlexfecSender outputs FlexFEC packets,
the main difference with ProducerFec is that FlexfecSender
allocates RTP sequence numbers, whereas ProducerFec does not
do this for the RED-encapsulated ULPFEC packets.

This class is split as interface/implementation, since it will
be owned by VideoSendStream initially. Further along, it may be
owned by PacedSender.

BUG=webrtc:5654

Review-Url: https://codereview.webrtc.org/2441613002
Cr-Commit-Position: refs/heads/master@{#14922}
This commit is contained in:
brandtr 2016-11-03 09:22:33 -07:00 committed by Commit bot
parent fb0c573263
commit c295e00fa0
8 changed files with 515 additions and 2 deletions

View File

@ -421,6 +421,7 @@ if (rtc_include_tests) {
"rtp_rtcp/source/fec_test_helper.h",
"rtp_rtcp/source/flexfec_header_reader_writer_unittest.cc",
"rtp_rtcp/source/flexfec_receiver_unittest.cc",
"rtp_rtcp/source/flexfec_sender_unittest.cc",
"rtp_rtcp/source/mock/mock_rtp_payload_strategy.h",
"rtp_rtcp/source/nack_rtx_unittest.cc",
"rtp_rtcp/source/packet_loss_stats_unittest.cc",

View File

@ -11,6 +11,7 @@ import("../../build/webrtc.gni")
rtc_static_library("rtp_rtcp") {
sources = [
"include/flexfec_receiver.h",
"include/flexfec_sender.h",
"include/receive_statistics.h",
"include/remote_ntp_time_estimator.h",
"include/rtp_header_parser.h",
@ -28,6 +29,7 @@ rtc_static_library("rtp_rtcp") {
"source/flexfec_header_reader_writer.cc",
"source/flexfec_header_reader_writer.h",
"source/flexfec_receiver.cc",
"source/flexfec_sender.cc",
"source/forward_error_correction.cc",
"source/forward_error_correction.h",
"source/forward_error_correction_internal.cc",

View File

@ -0,0 +1,82 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
#define WEBRTC_MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_
#include <memory>
#include <vector>
#include "webrtc/base/basictypes.h"
#include "webrtc/base/random.h"
#include "webrtc/base/sequenced_task_checker.h"
#include "webrtc/config.h"
#include "webrtc/modules/include/module_common_types.h"
#include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "webrtc/modules/rtp_rtcp/source/ulpfec_generator.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace webrtc {
class RtpPacketToSend;
class FlexfecSender {
public:
FlexfecSender(int payload_type,
uint32_t ssrc,
uint32_t protected_media_ssrc,
const std::vector<RtpExtension>& rtp_header_extensions,
Clock* clock);
~FlexfecSender();
// Sets the FEC rate, max frames sent before FEC packets are sent,
// and what type of generator matrices are used.
void SetFecParameters(const FecProtectionParams& params);
// Adds a media packet to the internal buffer. When enough media packets
// have been added, the FEC packets are generated and stored internally.
// These FEC packets are then obtained by calling GetFecPackets().
// Returns true if the media packet was successfully added.
bool AddRtpPacketAndGenerateFec(const RtpPacketToSend& packet);
// Returns true if there are generated FEC packets available.
bool FecAvailable() const;
// Returns generated FlexFEC packets.
std::vector<std::unique_ptr<RtpPacketToSend>> GetFecPackets();
// Returns the overhead, per packet, for FlexFEC.
size_t MaxPacketOverhead() const;
private:
// Utility.
Clock* const clock_;
Random random_ GUARDED_BY(sequence_checker_);
int64_t last_generated_packet_ms_ GUARDED_BY(sequence_checker_);
rtc::SequencedTaskChecker sequence_checker_;
// Config.
const int payload_type_;
const uint32_t timestamp_offset_;
const uint32_t ssrc_;
const uint32_t protected_media_ssrc_;
// Sequence number of next packet to generate.
uint16_t seq_num_ GUARDED_BY(sequence_checker_);
// Implementation.
UlpfecGenerator ulpfec_generator_ GUARDED_BY(sequence_checker_);
RtpHeaderExtensionMap rtp_header_extension_map_ GUARDED_BY(sequence_checker_);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_INCLUDE_FLEXFEC_SENDER_H_

View File

@ -19,6 +19,7 @@
'sources': [
# Common
'include/flexfec_receiver.h',
'include/flexfec_sender.h',
'include/receive_statistics.h',
'include/remote_ntp_time_estimator.h',
'include/rtp_header_parser.h',
@ -134,6 +135,7 @@
'source/fec_private_tables_bursty.h',
'source/flexfec_header_reader_writer.cc',
'source/flexfec_header_reader_writer.h',
'source/flexfec_sender.cc',
'source/forward_error_correction.cc',
'source/forward_error_correction.h',
'source/forward_error_correction_internal.cc',

View File

@ -0,0 +1,165 @@
/*
* 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 "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
#include <utility>
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
namespace webrtc {
namespace {
// Let first sequence number be in the first half of the interval.
constexpr uint16_t kMaxInitRtpSeqNumber = 0x7fff;
// See breakdown in flexfec_header_reader_writer.cc.
constexpr size_t kFlexfecMaxHeaderSize = 32;
// Since we will mainly use FlexFEC to protect video streams, we use a 90 kHz
// clock for the RTP timestamps. (This is according to the RFC, which states
// that it is RECOMMENDED to use the same clock frequency for FlexFEC as for
// the protected media stream.)
// The constant converts from clock millisecond timestamps to the 90 kHz
// RTP timestamp.
const int kMsToRtpTimestamp = kVideoPayloadTypeFrequency / 1000;
// How often to log the generated FEC packets to the text log.
constexpr int64_t kPacketLogIntervalMs = 10000;
} // namespace
FlexfecSender::FlexfecSender(
int payload_type,
uint32_t ssrc,
uint32_t protected_media_ssrc,
const std::vector<RtpExtension>& rtp_header_extensions,
Clock* clock)
: clock_(clock),
random_(clock_->TimeInMicroseconds()),
last_generated_packet_ms_(-1),
payload_type_(payload_type),
// Initialize the timestamp offset and RTP sequence numbers randomly.
// (This is not intended to be cryptographically strong.)
timestamp_offset_(random_.Rand<uint32_t>()),
ssrc_(ssrc),
protected_media_ssrc_(protected_media_ssrc),
seq_num_(random_.Rand(1, kMaxInitRtpSeqNumber)),
ulpfec_generator_(ForwardErrorCorrection::CreateFlexfec()),
rtp_header_extension_map_() {
// This object should not have been instantiated if FlexFEC is disabled.
RTC_DCHECK_GE(payload_type, 0);
RTC_DCHECK_LE(payload_type, 127);
// It's OK to create this object on a different thread/task queue than
// the one used during main operation.
sequence_checker_.Detach();
// Register RTP header extensions for BWE.
for (const auto& extension : rtp_header_extensions) {
if (extension.uri == RtpExtension::kTransportSequenceNumberUri) {
rtp_header_extension_map_.Register(kRtpExtensionTransportSequenceNumber,
extension.id);
} else if (extension.uri == RtpExtension::kAbsSendTimeUri) {
rtp_header_extension_map_.Register(kRtpExtensionAbsoluteSendTime,
extension.id);
} else if (extension.uri == RtpExtension::kTimestampOffsetUri) {
rtp_header_extension_map_.Register(kRtpExtensionTransmissionTimeOffset,
extension.id);
} else {
LOG(LS_WARNING) << "RTP header extension with id: " << extension.id
<< ", uri: " << extension.uri
<< ", is unsupported by FlexfecSender.";
}
}
}
FlexfecSender::~FlexfecSender() = default;
// We are reusing the implementation from UlpfecGenerator for SetFecParameters,
// AddRtpPacketAndGenerateFec, and FecAvailable.
void FlexfecSender::SetFecParameters(const FecProtectionParams& params) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
ulpfec_generator_.SetFecParameters(&params);
}
bool FlexfecSender::AddRtpPacketAndGenerateFec(
const RtpPacketToSend& packet) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
// TODO(brandtr): Generalize this SSRC check when we support multistream
// protection.
RTC_DCHECK_EQ(packet.Ssrc(), protected_media_ssrc_);
return ulpfec_generator_.AddRtpPacketAndGenerateFec(
packet.data(), packet.payload_size(), packet.headers_size()) == 0;
}
bool FlexfecSender::FecAvailable() const {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
return ulpfec_generator_.FecAvailable();
}
std::vector<std::unique_ptr<RtpPacketToSend>>
FlexfecSender::GetFecPackets() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets_to_send;
fec_packets_to_send.reserve(ulpfec_generator_.generated_fec_packets_.size());
for (const auto& fec_packet : ulpfec_generator_.generated_fec_packets_) {
std::unique_ptr<RtpPacketToSend> fec_packet_to_send(
new RtpPacketToSend(&rtp_header_extension_map_));
// RTP header.
fec_packet_to_send->SetMarker(false);
fec_packet_to_send->SetPayloadType(payload_type_);
fec_packet_to_send->SetSequenceNumber(seq_num_++);
fec_packet_to_send->SetTimestamp(
timestamp_offset_ +
static_cast<uint32_t>(kMsToRtpTimestamp *
clock_->TimeInMilliseconds()));
// Set "capture time" so that the TransmissionOffset header extension
// can be set by the RTPSender.
fec_packet_to_send->set_capture_time_ms(clock_->TimeInMilliseconds());
fec_packet_to_send->SetSsrc(ssrc_);
// Reserve extensions, if registered. These will be set by the RTPSender.
fec_packet_to_send->ReserveExtension<AbsoluteSendTime>();
fec_packet_to_send->ReserveExtension<TransmissionOffset>();
fec_packet_to_send->ReserveExtension<TransportSequenceNumber>();
// RTP payload.
uint8_t* payload = fec_packet_to_send->AllocatePayload(fec_packet->length);
memcpy(payload, fec_packet->data, fec_packet->length);
fec_packets_to_send.push_back(std::move(fec_packet_to_send));
}
ulpfec_generator_.ResetState();
// TODO(brandtr): Remove this log output when the FlexFEC subsystem is
// properly wired up in a robust way.
int64_t now_ms = clock_->TimeInMilliseconds();
if (!fec_packets_to_send.empty() &&
now_ms - last_generated_packet_ms_ > kPacketLogIntervalMs) {
LOG(LS_INFO) << "Generated " << fec_packets_to_send.size()
<< " FlexFEC packets with payload type: " << payload_type_
<< " and SSRC: " << ssrc_ << ".";
last_generated_packet_ms_ = now_ms;
}
return fec_packets_to_send;
}
size_t FlexfecSender::MaxPacketOverhead() const {
return kFlexfecMaxHeaderSize;
}
} // namespace webrtc

View File

@ -0,0 +1,252 @@
/*
* 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 = 28732;
constexpr uint32_t kDeterministicTimestamp = 2305613085;
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->SetFecParameters(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, packet->length);
EXPECT_TRUE(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);
FlexfecSender sender(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);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoRtpHeaderExtensions, &clock);
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) {
// 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;
SimulatedClock clock(kInitialSimulatedClockTime);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoRtpHeaderExtensions, &clock);
sender.SetFecParameters(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, packet->length);
EXPECT_TRUE(sender.AddRtpPacketAndGenerateFec(rtp_packet));
}
}
EXPECT_TRUE(sender.FecAvailable());
std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
sender.GetFecPackets();
EXPECT_FALSE(sender.FecAvailable());
ASSERT_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) {
// 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;
SimulatedClock clock(kInitialSimulatedClockTime);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoRtpHeaderExtensions, &clock);
sender.SetFecParameters(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, packet->length);
EXPECT_TRUE(sender.AddRtpPacketAndGenerateFec(rtp_packet));
}
EXPECT_TRUE(sender.FecAvailable());
std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets =
sender.GetFecPackets();
EXPECT_FALSE(sender.FecAvailable());
ASSERT_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);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kRtpHeaderExtensions, &clock);
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) {
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kAbsSendTimeUri, 1}};
SimulatedClock clock(kInitialSimulatedClockTime);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kRtpHeaderExtensions, &clock);
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) {
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kTimestampOffsetUri, 1}};
SimulatedClock clock(kInitialSimulatedClockTime);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kRtpHeaderExtensions, &clock);
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) {
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kTransportSequenceNumberUri, 1}};
SimulatedClock clock(kInitialSimulatedClockTime);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kRtpHeaderExtensions, &clock);
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) {
const std::vector<RtpExtension> kRtpHeaderExtensions{
{RtpExtension::kAbsSendTimeUri, 1},
{RtpExtension::kTimestampOffsetUri, 2},
{RtpExtension::kTransportSequenceNumberUri, 3}};
SimulatedClock clock(kInitialSimulatedClockTime);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kRtpHeaderExtensions, &clock);
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);
FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc,
kNoRtpHeaderExtensions, &clock);
EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead());
}
} // namespace webrtc

View File

@ -94,7 +94,10 @@ size_t RedPacket::length() const {
}
UlpfecGenerator::UlpfecGenerator()
: fec_(ForwardErrorCorrection::CreateUlpfec()),
: UlpfecGenerator(ForwardErrorCorrection::CreateUlpfec()) {}
UlpfecGenerator::UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec)
: fec_(std::move(fec)),
num_protected_frames_(0),
min_num_media_packets_(1) {
memset(&params_, 0, sizeof(params_));
@ -140,7 +143,7 @@ int UlpfecGenerator::AddRtpPacketAndGenerateFec(const uint8_t* data_buffer,
bool complete_frame = false;
const bool marker_bit = (data_buffer[1] & kRtpMarkerBitMask) ? true : false;
if (media_packets_.size() < kUlpfecMaxMediaPackets) {
// Generic FEC can only protect up to |kUlpfecMaxMediaPackets| packets.
// Our packet masks can only protect up to |kUlpfecMaxMediaPackets| packets.
std::unique_ptr<ForwardErrorCorrection::Packet> packet(
new ForwardErrorCorrection::Packet());
packet->length = payload_length + rtp_header_length;

View File

@ -19,6 +19,8 @@
namespace webrtc {
class FlexfecSenderImpl;
class RedPacket {
public:
explicit RedPacket(size_t length);
@ -40,6 +42,8 @@ class RedPacket {
};
class UlpfecGenerator {
friend class FlexfecSender;
public:
UlpfecGenerator();
~UlpfecGenerator();
@ -74,6 +78,8 @@ class UlpfecGenerator {
size_t rtp_header_length);
private:
explicit UlpfecGenerator(std::unique_ptr<ForwardErrorCorrection> fec);
// Overhead is defined as relative to the number of media packets, and not
// relative to total number of packets. This definition is inherited from the
// protection factor produced by video_coding module and how the FEC