From dec73a816496ee0b095be6d447146c1fd62ee8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Spr=C3=A5ng?= Date: Mon, 26 Apr 2021 17:14:27 +0200 Subject: [PATCH] Add pure RtpSenderEgress unit test fixture. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extracts and refactors some test code from rtp_sender_unittest.cc and puts it in a new target intended to only test RtpSenderEgress, and do it as pure unit test, rather than the unholy not-quite-unit-not-quite-integration-test thingy we have today. Only a first test case is actually ported with this CL, but it's a start... Bug: webrtc:11340 Change-Id: Ie2cdde63a00a6ff6eba7b8d443eeb76ce2a527c9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/216180 Reviewed-by: Danil Chapovalov Commit-Queue: Erik Språng Cr-Commit-Position: refs/heads/master@{#33841} --- modules/rtp_rtcp/BUILD.gn | 2 + .../source/rtp_sender_egress_unittest.cc | 228 ++++++++++++++++++ .../rtp_rtcp/source/rtp_sender_unittest.cc | 38 --- 3 files changed, 230 insertions(+), 38 deletions(-) create mode 100644 modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index a42c1784ee..18c1d0d159 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn @@ -531,6 +531,7 @@ if (rtc_include_tests) { "source/rtp_rtcp_impl2_unittest.cc", "source/rtp_rtcp_impl_unittest.cc", "source/rtp_sender_audio_unittest.cc", + "source/rtp_sender_egress_unittest.cc", "source/rtp_sender_unittest.cc", "source/rtp_sender_video_unittest.cc", "source/rtp_sequence_number_map_unittest.cc", @@ -566,6 +567,7 @@ if (rtc_include_tests) { "../../api/rtc_event_log", "../../api/transport:field_trial_based_config", "../../api/transport/rtp:dependency_descriptor", + "../../api/units:data_size", "../../api/units:timestamp", "../../api/video:encoded_image", "../../api/video:video_bitrate_allocation", diff --git a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc new file mode 100644 index 0000000000..7712cd34d9 --- /dev/null +++ b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2021 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/source/rtp_sender_egress.h" + +#include + +#include "absl/types/optional.h" +#include "api/array_view.h" +#include "api/call/transport.h" +#include "api/units/data_size.h" +#include "api/units/timestamp.h" +#include "logging/rtc_event_log/mock/mock_rtc_event_log.h" +#include "modules/rtp_rtcp/include/rtp_rtcp.h" +#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/rtp_header_extensions.h" +#include "modules/rtp_rtcp/source/rtp_packet_history.h" +#include "modules/rtp_rtcp/source/rtp_packet_received.h" +#include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "test/gmock.h" +#include "test/gtest.h" +#include "test/time_controller/simulated_time_controller.h" + +namespace webrtc { +namespace { + +using ::testing::Field; +using ::testing::NiceMock; +using ::testing::StrictMock; + +constexpr Timestamp kStartTime = Timestamp::Millis(123456789); +constexpr int kDefaultPayloadType = 100; +constexpr uint16_t kStartSequenceNumber = 33; +constexpr uint32_t kSsrc = 725242; +constexpr uint32_t kRtxSsrc = 12345; +enum : int { + kTransportSequenceNumberExtensionId = 1, +}; + +struct TestConfig { + explicit TestConfig(bool with_overhead) : with_overhead(with_overhead) {} + bool with_overhead = false; +}; + +class MockSendPacketObserver : public SendPacketObserver { + public: + MOCK_METHOD(void, OnSendPacket, (uint16_t, int64_t, uint32_t), (override)); +}; + +class MockTransportFeedbackObserver : public TransportFeedbackObserver { + public: + MOCK_METHOD(void, OnAddPacket, (const RtpPacketSendInfo&), (override)); + MOCK_METHOD(void, + OnTransportFeedback, + (const rtcp::TransportFeedback&), + (override)); +}; + +class MockStreamDataCountersCallback : public StreamDataCountersCallback { + public: + MOCK_METHOD(void, + DataCountersUpdated, + (const StreamDataCounters& counters, uint32_t ssrc), + (override)); +}; + +class FieldTrialConfig : public WebRtcKeyValueConfig { + public: + FieldTrialConfig() : overhead_enabled_(false) {} + ~FieldTrialConfig() override {} + + void SetOverHeadEnabled(bool enabled) { overhead_enabled_ = enabled; } + + std::string Lookup(absl::string_view key) const override { + if (key == "WebRTC-SendSideBwe-WithOverhead") { + return overhead_enabled_ ? "Enabled" : "Disabled"; + } + return ""; + } + + private: + bool overhead_enabled_; +}; + +struct TransmittedPacket { + TransmittedPacket(rtc::ArrayView data, + const PacketOptions& packet_options, + RtpHeaderExtensionMap* extensions) + : packet(extensions), options(packet_options) { + EXPECT_TRUE(packet.Parse(data)); + } + RtpPacketReceived packet; + PacketOptions options; +}; + +class TestTransport : public Transport { + public: + explicit TestTransport(RtpHeaderExtensionMap* extensions) + : total_data_sent_(DataSize::Zero()), extensions_(extensions) {} + bool SendRtp(const uint8_t* packet, + size_t length, + const PacketOptions& options) override { + total_data_sent_ += DataSize::Bytes(length); + last_packet_.emplace(rtc::MakeArrayView(packet, length), options, + extensions_); + return true; + } + + bool SendRtcp(const uint8_t*, size_t) override { RTC_CHECK_NOTREACHED(); } + + absl::optional last_packet() { return last_packet_; } + + private: + DataSize total_data_sent_; + absl::optional last_packet_; + RtpHeaderExtensionMap* const extensions_; +}; + +} // namespace + +class RtpSenderEgressTest : public ::testing::TestWithParam { + protected: + RtpSenderEgressTest() + : time_controller_(kStartTime), + clock_(time_controller_.GetClock()), + transport_(&header_extensions_), + packet_history_(clock_, /*enable_rtx_padding_prioritization=*/true), + sequence_number_(kStartSequenceNumber) { + trials_.SetOverHeadEnabled(GetParam().with_overhead); + } + + std::unique_ptr CreateRtpSenderEgress() { + return std::make_unique(DefaultConfig(), &packet_history_); + } + + RtpRtcp::Configuration DefaultConfig() { + RtpRtcp::Configuration config; + config.clock = clock_; + config.outgoing_transport = &transport_; + config.local_media_ssrc = kSsrc; + config.rtx_send_ssrc = kRtxSsrc; + config.fec_generator = nullptr; + config.event_log = &mock_rtc_event_log_; + config.send_packet_observer = &send_packet_observer_; + config.rtp_stats_callback = &mock_rtp_stats_callback_; + config.transport_feedback_callback = &feedback_observer_; + config.populate_network2_timestamp = false; + config.field_trials = &trials_; + return config; + } + + std::unique_ptr BuildRtpPacket(bool marker_bit, + int64_t capture_time_ms) { + auto packet = std::make_unique(&header_extensions_); + packet->SetSsrc(kSsrc); + packet->ReserveExtension(); + packet->ReserveExtension(); + packet->ReserveExtension(); + + packet->SetPayloadType(kDefaultPayloadType); + packet->set_packet_type(RtpPacketMediaType::kVideo); + packet->SetMarker(marker_bit); + packet->SetTimestamp(capture_time_ms * 90); + packet->set_capture_time_ms(capture_time_ms); + packet->SetSequenceNumber(sequence_number_++); + return packet; + } + + std::unique_ptr BuildRtpPacket() { + return BuildRtpPacket(/*marker_bit=*/true, clock_->CurrentTime().ms()); + } + + GlobalSimulatedTimeController time_controller_; + Clock* const clock_; + NiceMock mock_rtc_event_log_; + StrictMock mock_rtp_stats_callback_; + NiceMock send_packet_observer_; + NiceMock feedback_observer_; + RtpHeaderExtensionMap header_extensions_; + TestTransport transport_; + RtpPacketHistory packet_history_; + FieldTrialConfig trials_; + uint16_t sequence_number_; +}; + +TEST_P(RtpSenderEgressTest, TransportFeedbackObserverGetsCorrectByteCount) { + constexpr size_t kRtpOverheadBytesPerPacket = 12 + 8; + constexpr size_t kPayloadSize = 1400; + const uint16_t kTransportSequenceNumber = 17; + + header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId, + TransportSequenceNumber::kUri); + + const size_t expected_bytes = GetParam().with_overhead + ? kPayloadSize + kRtpOverheadBytesPerPacket + : kPayloadSize; + + EXPECT_CALL( + feedback_observer_, + OnAddPacket(AllOf( + Field(&RtpPacketSendInfo::ssrc, kSsrc), + Field(&RtpPacketSendInfo::transport_sequence_number, + kTransportSequenceNumber), + Field(&RtpPacketSendInfo::rtp_sequence_number, kStartSequenceNumber), + Field(&RtpPacketSendInfo::length, expected_bytes), + Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo())))); + + std::unique_ptr packet = BuildRtpPacket(); + packet->SetExtension(kTransportSequenceNumber); + packet->AllocatePayload(kPayloadSize); + + std::unique_ptr sender = CreateRtpSenderEgress(); + sender->SendPacket(packet.get(), PacedPacketInfo()); +} + +INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead, + RtpSenderEgressTest, + ::testing::Values(TestConfig(false), + TestConfig(true))); + +} // namespace webrtc diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 709f96198c..e28cd596cf 100644 --- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -545,44 +545,6 @@ TEST_P(RtpSenderTest, PaddingAlwaysAllowedOnAudio) { EXPECT_EQ(kMinPaddingSize, GenerateAndSendPadding(kMinPaddingSize - 5)); } -TEST_P(RtpSenderTestWithoutPacer, - TransportFeedbackObserverGetsCorrectByteCount) { - constexpr size_t kRtpOverheadBytesPerPacket = 12 + 8; - constexpr size_t kPayloadSize = 1400; - - RtpRtcpInterface::Configuration config; - config.clock = clock_; - config.outgoing_transport = &transport_; - config.local_media_ssrc = kSsrc; - config.transport_feedback_callback = &feedback_observer_; - config.event_log = &mock_rtc_event_log_; - config.retransmission_rate_limiter = &retransmission_rate_limiter_; - config.field_trials = &field_trials_; - rtp_sender_context_ = - std::make_unique(config, &time_controller_); - - EXPECT_TRUE(rtp_sender()->RegisterRtpHeaderExtension( - TransportSequenceNumber::kUri, kTransportSequenceNumberExtensionId)); - - const size_t expected_bytes = GetParam().with_overhead - ? kPayloadSize + kRtpOverheadBytesPerPacket - : kPayloadSize; - - EXPECT_CALL(feedback_observer_, - OnAddPacket(AllOf( - Field(&RtpPacketSendInfo::ssrc, rtp_sender()->SSRC()), - Field(&RtpPacketSendInfo::transport_sequence_number, - kTransportSequenceNumber), - Field(&RtpPacketSendInfo::rtp_sequence_number, - rtp_sender()->SequenceNumber()), - Field(&RtpPacketSendInfo::length, expected_bytes), - Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo())))) - .Times(1); - EXPECT_EQ(rtp_sender()->ExpectedPerPacketOverhead(), - kRtpOverheadBytesPerPacket); - SendPacket(clock_->TimeInMilliseconds(), kPayloadSize); -} - TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) { RtpRtcpInterface::Configuration config; config.clock = clock_;