From c295e00fa0a9774acbadf5d54389b46b1c17965e Mon Sep 17 00:00:00 2001 From: brandtr Date: Thu, 3 Nov 2016 09:22:33 -0700 Subject: [PATCH] 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} --- webrtc/modules/BUILD.gn | 1 + webrtc/modules/rtp_rtcp/BUILD.gn | 2 + .../modules/rtp_rtcp/include/flexfec_sender.h | 82 ++++++ webrtc/modules/rtp_rtcp/rtp_rtcp.gypi | 2 + .../modules/rtp_rtcp/source/flexfec_sender.cc | 165 ++++++++++++ .../source/flexfec_sender_unittest.cc | 252 ++++++++++++++++++ .../rtp_rtcp/source/ulpfec_generator.cc | 7 +- .../rtp_rtcp/source/ulpfec_generator.h | 6 + 8 files changed, 515 insertions(+), 2 deletions(-) create mode 100644 webrtc/modules/rtp_rtcp/include/flexfec_sender.h create mode 100644 webrtc/modules/rtp_rtcp/source/flexfec_sender.cc create mode 100644 webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index a7ea1191ff..13f74f85ea 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -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", diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn index e373801f3e..66183a85a1 100644 --- a/webrtc/modules/rtp_rtcp/BUILD.gn +++ b/webrtc/modules/rtp_rtcp/BUILD.gn @@ -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", diff --git a/webrtc/modules/rtp_rtcp/include/flexfec_sender.h b/webrtc/modules/rtp_rtcp/include/flexfec_sender.h new file mode 100644 index 0000000000..f50dfb6b39 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/include/flexfec_sender.h @@ -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 +#include + +#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& 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> 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_ diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi index b58f9e48bf..cf5b3095de 100644 --- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi +++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi @@ -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', diff --git a/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc b/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc new file mode 100644 index 0000000000..9f04161e52 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/flexfec_sender.cc @@ -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 + +#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& 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()), + 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(¶ms); +} + +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> +FlexfecSender::GetFecPackets() { + RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_); + + std::vector> 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 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(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(); + fec_packet_to_send->ReserveExtension(); + fec_packet_to_send->ReserveExtension(); + + // 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 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 0000000000..ca114abeb3 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/flexfec_sender_unittest.cc @@ -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 + +#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 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 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 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> 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 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> 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 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> 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(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 kRtpHeaderExtensions{}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_FALSE(fec_packet->HasExtension()); + EXPECT_FALSE(fec_packet->HasExtension()); + EXPECT_FALSE(fec_packet->HasExtension()); +} + +TEST(FlexfecSenderTest, RegisterAbsoluteSendTimeRtpHeaderExtension) { + const std::vector kRtpHeaderExtensions{ + {RtpExtension::kAbsSendTimeUri, 1}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_TRUE(fec_packet->HasExtension()); + EXPECT_FALSE(fec_packet->HasExtension()); + EXPECT_FALSE(fec_packet->HasExtension()); +} + +TEST(FlexfecSenderTest, RegisterTransmissionOffsetRtpHeaderExtension) { + const std::vector kRtpHeaderExtensions{ + {RtpExtension::kTimestampOffsetUri, 1}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_FALSE(fec_packet->HasExtension()); + EXPECT_TRUE(fec_packet->HasExtension()); + EXPECT_FALSE(fec_packet->HasExtension()); +} + +TEST(FlexfecSenderTest, RegisterTransportSequenceNumberRtpHeaderExtension) { + const std::vector kRtpHeaderExtensions{ + {RtpExtension::kTransportSequenceNumberUri, 1}}; + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kRtpHeaderExtensions, &clock); + auto fec_packet = GenerateSingleFlexfecPacket(&sender); + + EXPECT_FALSE(fec_packet->HasExtension()); + EXPECT_FALSE(fec_packet->HasExtension()); + EXPECT_TRUE(fec_packet->HasExtension()); +} + +TEST(FlexfecSenderTest, RegisterAllRtpHeaderExtensionsForBwe) { + const std::vector 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()); + EXPECT_TRUE(fec_packet->HasExtension()); + EXPECT_TRUE(fec_packet->HasExtension()); +} + +TEST(FlexfecSenderTest, MaxPacketOverhead) { + SimulatedClock clock(kInitialSimulatedClockTime); + FlexfecSender sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpHeaderExtensions, &clock); + + EXPECT_EQ(kFlexfecMaxHeaderSize, sender.MaxPacketOverhead()); +} + +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc b/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc index 3c71c63835..c9de401d71 100644 --- a/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc +++ b/webrtc/modules/rtp_rtcp/source/ulpfec_generator.cc @@ -94,7 +94,10 @@ size_t RedPacket::length() const { } UlpfecGenerator::UlpfecGenerator() - : fec_(ForwardErrorCorrection::CreateUlpfec()), + : UlpfecGenerator(ForwardErrorCorrection::CreateUlpfec()) {} + +UlpfecGenerator::UlpfecGenerator(std::unique_ptr fec) + : fec_(std::move(fec)), num_protected_frames_(0), min_num_media_packets_(1) { memset(¶ms_, 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 packet( new ForwardErrorCorrection::Packet()); packet->length = payload_length + rtp_header_length; diff --git a/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h b/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h index 33c4d09c39..e5b6064ccc 100644 --- a/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h +++ b/webrtc/modules/rtp_rtcp/source/ulpfec_generator.h @@ -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 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