blob: 7712cd34d9ebf95521e164a571ac07b6344b30c3 [file] [log] [blame]
/*
* 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 <string>
#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<const uint8_t> 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<TransmittedPacket> last_packet() { return last_packet_; }
private:
DataSize total_data_sent_;
absl::optional<TransmittedPacket> last_packet_;
RtpHeaderExtensionMap* const extensions_;
};
} // namespace
class RtpSenderEgressTest : public ::testing::TestWithParam<TestConfig> {
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<RtpSenderEgress> CreateRtpSenderEgress() {
return std::make_unique<RtpSenderEgress>(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<RtpPacketToSend> BuildRtpPacket(bool marker_bit,
int64_t capture_time_ms) {
auto packet = std::make_unique<RtpPacketToSend>(&header_extensions_);
packet->SetSsrc(kSsrc);
packet->ReserveExtension<AbsoluteSendTime>();
packet->ReserveExtension<TransmissionOffset>();
packet->ReserveExtension<TransportSequenceNumber>();
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<RtpPacketToSend> BuildRtpPacket() {
return BuildRtpPacket(/*marker_bit=*/true, clock_->CurrentTime().ms());
}
GlobalSimulatedTimeController time_controller_;
Clock* const clock_;
NiceMock<MockRtcEventLog> mock_rtc_event_log_;
StrictMock<MockStreamDataCountersCallback> mock_rtp_stats_callback_;
NiceMock<MockSendPacketObserver> send_packet_observer_;
NiceMock<MockTransportFeedbackObserver> 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<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
packet->AllocatePayload(kPayloadSize);
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
sender->SendPacket(packet.get(), PacedPacketInfo());
}
INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
RtpSenderEgressTest,
::testing::Values(TestConfig(false),
TestConfig(true)));
} // namespace webrtc