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