diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 72a1f11f42..15fb325575 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -74,6 +74,7 @@ ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration) configuration.clock, configuration.outgoing_transport, configuration.paced_sender, + nullptr, // TODO(brandtr): Wire up FlexfecSender here. configuration.transport_sequence_number_allocator, configuration.transport_feedback_callback, configuration.send_bitrate_observer, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index fafbf11bae..36915c53af 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -67,6 +67,7 @@ RTPSender::RTPSender( Clock* clock, Transport* transport, RtpPacketSender* paced_sender, + FlexfecSender* flexfec_sender, TransportSequenceNumberAllocator* sequence_number_allocator, TransportFeedbackObserver* transport_feedback_observer, BitrateStatisticsObserver* bitrate_callback, @@ -81,7 +82,7 @@ RTPSender::RTPSender( random_(clock_->TimeInMicroseconds()), audio_configured_(audio), audio_(audio ? new RTPSenderAudio(clock, this) : nullptr), - video_(audio ? nullptr : new RTPSenderVideo(clock, this)), + video_(audio ? nullptr : new RTPSenderVideo(clock, this, flexfec_sender)), paced_sender_(paced_sender), transport_sequence_number_allocator_(sequence_number_allocator), transport_feedback_observer_(transport_feedback_observer), diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index c589d0bbbe..09bcebc640 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -23,6 +23,7 @@ #include "webrtc/base/rate_statistics.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/common_types.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/playout_delay_oracle.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" @@ -46,6 +47,9 @@ class RTPSender { Clock* clock, Transport* transport, RtpPacketSender* paced_sender, + // TODO(brandtr): Remove |flexfec_sender| when that is hooked up + // to PacedSender instead. + FlexfecSender* flexfec_sender, TransportSequenceNumberAllocator* sequence_number_allocator, TransportFeedbackObserver* transport_feedback_callback, BitrateStatisticsObserver* bitrate_callback, diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index d02d25eb21..d6796e7880 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -147,7 +147,7 @@ class RtpSenderTest : public ::testing::Test { void SetUpRtpSender(bool pacer) { rtp_sender_.reset(new RTPSender( false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr, - &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, + nullptr, &seq_num_allocator_, nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, &send_packet_observer_, &retransmission_rate_limiter_)); rtp_sender_->SetSequenceNumber(kSeqNum); @@ -239,7 +239,7 @@ class RtpSenderVideoTest : public RtpSenderTest { // TODO(pbos): Set up to use pacer. SetUpRtpSender(false); rtp_sender_video_.reset( - new RTPSenderVideo(&fake_clock_, rtp_sender_.get())); + new RTPSenderVideo(&fake_clock_, rtp_sender_.get(), nullptr)); } std::unique_ptr rtp_sender_video_; }; @@ -440,10 +440,9 @@ TEST_F(RtpSenderTestWithoutPacer, AssignSequenceNumberSetPaddingTimestamps) { TEST_F(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) { rtp_sender_.reset(new RTPSender( - false, &fake_clock_, &transport_, nullptr, - &seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr, - &mock_rtc_event_log_, &send_packet_observer_, - &retransmission_rate_limiter_)); + false, &fake_clock_, &transport_, nullptr, nullptr, &seq_num_allocator_, + &feedback_observer_, nullptr, nullptr, nullptr, &mock_rtc_event_log_, + &send_packet_observer_, &retransmission_rate_limiter_)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); @@ -486,11 +485,11 @@ TEST_F(RtpSenderTestWithoutPacer, OnSendPacketUpdated) { } TEST_F(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) { - rtp_sender_.reset(new RTPSender( - false, &fake_clock_, &transport_, &mock_paced_sender_, - &seq_num_allocator_, &feedback_observer_, nullptr, nullptr, nullptr, - &mock_rtc_event_log_, &send_packet_observer_, - &retransmission_rate_limiter_)); + rtp_sender_.reset( + new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_, + nullptr, &seq_num_allocator_, &feedback_observer_, nullptr, + nullptr, nullptr, &mock_rtc_event_log_, + &send_packet_observer_, &retransmission_rate_limiter_)); rtp_sender_->SetStorePacketsStatus(true, 10); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, @@ -768,7 +767,7 @@ TEST_F(RtpSenderTest, OnSendPacketNotUpdatedForRetransmits) { TEST_F(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) { rtp_sender_.reset(new RTPSender( - false, &fake_clock_, &transport_, &mock_paced_sender_, + false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr /* TransportSequenceNumberAllocator */, nullptr, nullptr, nullptr, nullptr, nullptr, &send_packet_observer_, &retransmission_rate_limiter_)); EXPECT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension( @@ -791,7 +790,7 @@ TEST_F(RtpSenderTest, SendRedundantPayloads) { MockTransport transport; rtp_sender_.reset(new RTPSender( false, &fake_clock_, &transport, &mock_paced_sender_, nullptr, nullptr, - nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr, + nullptr, nullptr, nullptr, nullptr, &mock_rtc_event_log_, nullptr, &retransmission_rate_limiter_)); rtp_sender_->SetSequenceNumber(kSeqNum); @@ -900,6 +899,93 @@ TEST_F(RtpSenderTestWithoutPacer, SendGenericVideo) { EXPECT_EQ(0, memcmp(payload, payload_data, sizeof(payload))); } +TEST_F(RtpSenderTest, SendFlexfecPackets) { + constexpr int kMediaPayloadType = 127; + constexpr int kFlexfecPayloadType = 118; + constexpr uint32_t kMediaSsrc = 1234; + constexpr uint32_t kFlexfecSsrc = 5678; + const std::vector kNoRtpExtensions; + FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpExtensions, &fake_clock_); + + // Reset |rtp_sender_| to use FlexFEC. + rtp_sender_.reset( + new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_, + &flexfec_sender, &seq_num_allocator_, nullptr, nullptr, + nullptr, nullptr, &mock_rtc_event_log_, + &send_packet_observer_, &retransmission_rate_limiter_)); + rtp_sender_->SetSSRC(kMediaSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSendPayloadType(kMediaPayloadType); + rtp_sender_->SetStorePacketsStatus(true, 10); + + // Parameters selected to generate a single FEC packet per media packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + rtp_sender_->SetFecParameters(params, params); + + uint16_t media_seq_num; + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority, + kMediaSsrc, _, _, _, false)) + .WillOnce(testing::SaveArg<2>(&media_seq_num)); + EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority, + kFlexfecSsrc, _, _, _, false)); + SendGenericPayload(); + // TODO(brandtr): Make these tests stricter when the FlexFEC packets are no + // longer lost between PacedSender and RTPSender. + EXPECT_CALL(mock_rtc_event_log_, + LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _)) + .Times(testing::AtLeast(1)); + EXPECT_TRUE(rtp_sender_->TimeToSendPacket( + media_seq_num, fake_clock_.TimeInMilliseconds(), false, 0)); + EXPECT_LE(1, transport_.packets_sent()); + const RtpPacketReceived& media_packet = transport_.sent_packets_[0]; + EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType()); + EXPECT_EQ(media_seq_num, media_packet.SequenceNumber()); + EXPECT_EQ(kMediaSsrc, media_packet.Ssrc()); +} + +TEST_F(RtpSenderTestWithoutPacer, SendFlexfecPackets) { + constexpr int kMediaPayloadType = 127; + constexpr int kFlexfecPayloadType = 118; + constexpr uint32_t kMediaSsrc = 1234; + constexpr uint32_t kFlexfecSsrc = 5678; + const std::vector kNoRtpExtensions; + FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kMediaSsrc, + kNoRtpExtensions, &fake_clock_); + + // Reset |rtp_sender_| to use FlexFEC. + rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr, + &flexfec_sender, &seq_num_allocator_, nullptr, + nullptr, nullptr, nullptr, + &mock_rtc_event_log_, &send_packet_observer_, + &retransmission_rate_limiter_)); + rtp_sender_->SetSSRC(kMediaSsrc); + rtp_sender_->SetSequenceNumber(kSeqNum); + rtp_sender_->SetSendPayloadType(kMediaPayloadType); + + // Parameters selected to generate a single FEC packet per media packet. + FecProtectionParams params; + params.fec_rate = 15; + params.max_fec_frames = 1; + params.fec_mask_type = kFecMaskRandom; + rtp_sender_->SetFecParameters(params, params); + + EXPECT_CALL(mock_rtc_event_log_, + LogRtpHeader(PacketDirection::kOutgoingPacket, _, _, _)) + .Times(2); + SendGenericPayload(); + ASSERT_EQ(2, transport_.packets_sent()); + const RtpPacketReceived& media_packet = transport_.sent_packets_[0]; + EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType()); + EXPECT_EQ(kMediaSsrc, media_packet.Ssrc()); + const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[1]; + EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType()); + EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc()); +} + TEST_F(RtpSenderTest, FrameCountCallbacks) { class TestCallback : public FrameCountObserver { public: @@ -920,8 +1006,8 @@ TEST_F(RtpSenderTest, FrameCountCallbacks) { rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, &mock_paced_sender_, nullptr, nullptr, - nullptr, &callback, nullptr, nullptr, nullptr, - &retransmission_rate_limiter_)); + nullptr, nullptr, &callback, nullptr, nullptr, + nullptr, &retransmission_rate_limiter_)); char payload_name[RTP_PAYLOAD_NAME_SIZE] = "GENERIC"; const uint8_t payload_type = 127; @@ -980,9 +1066,10 @@ TEST_F(RtpSenderTest, BitrateCallbacks) { uint32_t total_bitrate_; uint32_t retransmit_bitrate_; } callback; - rtp_sender_.reset(new RTPSender( - false, &fake_clock_, &transport_, nullptr, nullptr, nullptr, &callback, - nullptr, nullptr, nullptr, nullptr, &retransmission_rate_limiter_)); + rtp_sender_.reset(new RTPSender(false, &fake_clock_, &transport_, nullptr, + nullptr, nullptr, nullptr, &callback, nullptr, + nullptr, nullptr, nullptr, + &retransmission_rate_limiter_)); // Simulate kNumPackets sent with kPacketInterval ms intervals, with the // number of packets selected so that we fill (but don't overflow) the one @@ -1037,9 +1124,10 @@ class RtpSenderAudioTest : public RtpSenderTest { void SetUp() override { payload_ = kAudioPayload; - rtp_sender_.reset(new RTPSender( - true, &fake_clock_, &transport_, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, &retransmission_rate_limiter_)); + rtp_sender_.reset(new RTPSender(true, &fake_clock_, &transport_, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + &retransmission_rate_limiter_)); rtp_sender_->SetSequenceNumber(kSeqNum); } }; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc index f80caeaf7e..4a007c53eb 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.cc @@ -44,7 +44,9 @@ void BuildRedPayload(const RtpPacketToSend& media_packet, } } // namespace -RTPSenderVideo::RTPSenderVideo(Clock* clock, RTPSender* rtp_sender) +RTPSenderVideo::RTPSenderVideo(Clock* clock, + RTPSender* rtp_sender, + FlexfecSender* flexfec_sender) : rtp_sender_(rtp_sender), clock_(clock), video_type_(kRtpVideoGeneric), @@ -52,7 +54,7 @@ RTPSenderVideo::RTPSenderVideo(Clock* clock, RTPSender* rtp_sender) last_rotation_(kVideoRotation_0), red_payload_type_(-1), ulpfec_payload_type_(-1), - flexfec_sender_(nullptr), // TODO(brandtr): Wire up in future CL. + flexfec_sender_(flexfec_sender), delta_fec_params_{0, 1, kFecMaskRandom}, key_fec_params_{0, 1, kFecMaskRandom}, fec_bitrate_(1000, RateStatistics::kBpsScale), diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h index cc5b551402..da016b767e 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_video.h @@ -35,7 +35,9 @@ class RtpPacketToSend; class RTPSenderVideo { public: - RTPSenderVideo(Clock* clock, RTPSender* rtpSender); + RTPSenderVideo(Clock* clock, + RTPSender* rtpSender, + FlexfecSender* flexfec_sender); virtual ~RTPSenderVideo(); virtual RtpVideoCodecTypes VideoCodecType() const;