webrtc_m130/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

928 lines
39 KiB
C++
Raw Normal View History

/*
* 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 <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <utility>
#include "api/array_view.h"
#include "api/call/transport.h"
#include "api/environment/environment.h"
#include "api/environment/environment_factory.h"
#include "api/transport/network_types.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "api/video/video_timing.h"
#include "modules/rtp_rtcp/include/flexfec_sender.h"
#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_header_extension_size.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 "modules/rtp_rtcp/source/rtp_rtcp_interface.h"
#include "rtc_base/checks.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/time_controller/simulated_time_controller.h"
namespace webrtc {
namespace {
using ::testing::_;
using ::testing::AllOf;
using ::testing::Eq;
using ::testing::Field;
using ::testing::InSequence;
using ::testing::NiceMock;
using ::testing::StrictMock;
constexpr Timestamp kStartTime = Timestamp::Millis(123456789);
constexpr int kDefaultPayloadType = 100;
constexpr int kFlexfectPayloadType = 110;
constexpr uint16_t kStartSequenceNumber = 33;
constexpr uint32_t kSsrc = 725242;
constexpr uint32_t kRtxSsrc = 12345;
constexpr uint32_t kFlexFecSsrc = 23456;
enum : int {
kTransportSequenceNumberExtensionId = 1,
kAbsoluteSendTimeExtensionId,
kTransmissionOffsetExtensionId,
kVideoTimingExtensionId,
};
class MockSendPacketObserver : public SendPacketObserver {
public:
MOCK_METHOD(void,
OnSendPacket,
(std::optional<uint16_t>, Timestamp, uint32_t),
(override));
};
class MockStreamDataCountersCallback : public StreamDataCountersCallback {
public:
MOCK_METHOD(void,
DataCountersUpdated,
(const StreamDataCounters& counters, uint32_t ssrc),
(override));
};
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) {}
MOCK_METHOD(void, SentRtp, (const PacketOptions& options), ());
bool SendRtp(rtc::ArrayView<const uint8_t> packet,
const PacketOptions& options) override {
total_data_sent_ += DataSize::Bytes(packet.size());
last_packet_.emplace(packet, options, extensions_);
SentRtp(options);
return true;
}
bool SendRtcp(rtc::ArrayView<const uint8_t>) override {
RTC_CHECK_NOTREACHED();
}
std::optional<TransmittedPacket> last_packet() { return last_packet_; }
private:
DataSize total_data_sent_;
std::optional<TransmittedPacket> last_packet_;
RtpHeaderExtensionMap* const extensions_;
};
} // namespace
class RtpSenderEgressTest : public ::testing::Test {
protected:
RtpSenderEgressTest()
: time_controller_(kStartTime),
env_(CreateEnvironment(time_controller_.GetClock())),
transport_(&header_extensions_),
packet_history_(env_,
RtpPacketHistory::PaddingMode::kRecentLargePacket),
sequence_number_(kStartSequenceNumber) {}
std::unique_ptr<RtpSenderEgress> CreateRtpSenderEgress() {
return std::make_unique<RtpSenderEgress>(env_, DefaultConfig(),
&packet_history_);
}
RtpRtcpInterface::Configuration DefaultConfig() {
RtpRtcpInterface::Configuration config;
config.audio = false;
config.outgoing_transport = &transport_;
config.local_media_ssrc = kSsrc;
config.rtx_send_ssrc = kRtxSsrc;
config.fec_generator = nullptr;
config.send_packet_observer = &send_packet_observer_;
config.rtp_stats_callback = &mock_rtp_stats_callback_;
config.populate_network2_timestamp = false;
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);
Reland "Represent RtpPacketToSend::capture_time with Timestamp" This reverts commit 56db8d09529d5ba92d24954a1d78a90c8ea2cd85. Reason for revert: downstream problem addressed Original change's description: > Revert "Represent RtpPacketToSend::capture_time with Timestamp" > > This reverts commit 385eb9714daa80306d2f92d36678c42892dab555. > > Reason for revert: Causes problems downstream: > > # > # Fatal error in: rtc_base/units/unit_base.h, line 122 > # last system error: 0 > # Check failed: value >= 0 (-234 vs. 0) > > Original change's description: > > Represent RtpPacketToSend::capture_time with Timestamp > > > > Bug: webrtc:13757 > > Change-Id: I0ede22cd34e3a59afe1477d8edd495dce64e3242 > > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/252586 > > Reviewed-by: Erik Språng <sprang@webrtc.org> > > Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> > > Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> > > Cr-Commit-Position: refs/heads/main@{#36083} > > Bug: webrtc:13757 > Change-Id: I8442abd438be8726cf671d0f372d50ecfac6847e > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/252720 > Auto-Submit: Tomas Gunnarsson <tommi@webrtc.org> > Bot-Commit: rubber-stamper@appspot.gserviceaccount.com <rubber-stamper@appspot.gserviceaccount.com> > Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org> > Cr-Commit-Position: refs/heads/main@{#36087} Bug: webrtc:13757 Change-Id: I1fa852757480116f35deb2b6c3c27800bdf5e197 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/252781 Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#36093}
2022-02-27 21:10:55 +00:00
packet->set_capture_time(Timestamp::Millis(capture_time_ms));
packet->SetSequenceNumber(sequence_number_++);
return packet;
}
std::unique_ptr<RtpPacketToSend> BuildRtpPacket() {
return BuildRtpPacket(/*marker_bit=*/true, env_.clock().CurrentTime().ms());
}
GlobalSimulatedTimeController time_controller_;
const Environment env_;
NiceMock<MockStreamDataCountersCallback> mock_rtp_stats_callback_;
NiceMock<MockSendPacketObserver> send_packet_observer_;
RtpHeaderExtensionMap header_extensions_;
NiceMock<TestTransport> transport_;
RtpPacketHistory packet_history_;
uint16_t sequence_number_;
};
TEST_F(RtpSenderEgressTest, SendsPacketsOneByOneWhenNotBatching) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
EXPECT_CALL(transport_,
SentRtp(AllOf(Field(&PacketOptions::last_packet_in_batch, false),
Field(&PacketOptions::batchable, false))));
sender->SendPacket(BuildRtpPacket(), PacedPacketInfo());
}
TEST_F(RtpSenderEgressTest, SendsPacketsOneByOneWhenBatchingWithAudio) {
auto config = DefaultConfig();
config.enable_send_packet_batching = true;
config.audio = true;
auto sender =
std::make_unique<RtpSenderEgress>(env_, config, &packet_history_);
EXPECT_CALL(transport_,
SentRtp(AllOf(Field(&PacketOptions::last_packet_in_batch, false),
Field(&PacketOptions::batchable, false))))
.Times(2);
sender->SendPacket(BuildRtpPacket(), PacedPacketInfo());
sender->SendPacket(BuildRtpPacket(), PacedPacketInfo());
}
TEST_F(RtpSenderEgressTest, CollectsPacketsWhenBatchingWithVideo) {
auto config = DefaultConfig();
config.enable_send_packet_batching = true;
RtpSenderEgress sender(env_, config, &packet_history_);
sender.SendPacket(BuildRtpPacket(), PacedPacketInfo());
sender.SendPacket(BuildRtpPacket(), PacedPacketInfo());
InSequence s;
EXPECT_CALL(transport_,
SentRtp(AllOf(Field(&PacketOptions::last_packet_in_batch, false),
Field(&PacketOptions::batchable, true))));
EXPECT_CALL(transport_,
SentRtp(AllOf(Field(&PacketOptions::last_packet_in_batch, true),
Field(&PacketOptions::batchable, true))));
sender.OnBatchComplete();
}
TEST_F(RtpSenderEgressTest, PacketOptionsIsRetransmitSetByPacketType) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
auto sequence_number = media_packet->SequenceNumber();
media_packet->set_packet_type(RtpPacketMediaType::kVideo);
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
EXPECT_FALSE(transport_.last_packet()->options.is_retransmit);
std::unique_ptr<RtpPacketToSend> retransmission = BuildRtpPacket();
retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
retransmission->set_retransmitted_sequence_number(sequence_number);
sender->SendPacket(std::move(retransmission), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.is_retransmit);
}
TEST_F(RtpSenderEgressTest, DoesnSetIncludedInAllocationByDefault) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_FALSE(transport_.last_packet()->options.included_in_feedback);
EXPECT_FALSE(transport_.last_packet()->options.included_in_allocation);
}
TEST_F(RtpSenderEgressTest,
SetsIncludedInFeedbackWhenTransportSequenceNumberExtensionIsRegistered) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(1);
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.included_in_feedback);
}
TEST_F(
RtpSenderEgressTest,
SetsIncludedInAllocationWhenTransportSequenceNumberExtensionIsRegistered) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(1);
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.included_in_allocation);
}
TEST_F(RtpSenderEgressTest,
SetsIncludedInAllocationWhenForcedAsPartOfAllocation) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
sender->ForceIncludeSendPacketsInAllocation(true);
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_FALSE(transport_.last_packet()->options.included_in_feedback);
EXPECT_TRUE(transport_.last_packet()->options.included_in_allocation);
}
TEST_F(RtpSenderEgressTest,
DoesntWriteTransmissionOffsetOnRtxPaddingBeforeMedia) {
header_extensions_.RegisterByUri(kTransmissionOffsetExtensionId,
TransmissionOffset::Uri());
// Prior to sending media, timestamps are 0.
std::unique_ptr<RtpPacketToSend> padding =
BuildRtpPacket(/*marker_bit=*/true, /*capture_time_ms=*/0);
padding->set_packet_type(RtpPacketMediaType::kPadding);
padding->SetSsrc(kRtxSsrc);
EXPECT_TRUE(padding->HasExtension<TransmissionOffset>());
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
sender->SendPacket(std::move(padding), PacedPacketInfo());
std::optional<int32_t> offset =
transport_.last_packet()->packet.GetExtension<TransmissionOffset>();
EXPECT_EQ(offset, 0);
}
TEST_F(RtpSenderEgressTest, WritesPacerExitToTimingExtension) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kVideoTimingExtensionId,
VideoTimingExtension::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetExtension<VideoTimingExtension>(VideoSendTiming{});
const int kStoredTimeInMs = 100;
time_controller_.AdvanceTime(TimeDelta::Millis(kStoredTimeInMs));
sender->SendPacket(std::move(packet), PacedPacketInfo());
ASSERT_TRUE(transport_.last_packet().has_value());
VideoSendTiming video_timing;
EXPECT_TRUE(
transport_.last_packet()->packet.GetExtension<VideoTimingExtension>(
&video_timing));
EXPECT_EQ(video_timing.pacer_exit_delta_ms, kStoredTimeInMs);
}
TEST_F(RtpSenderEgressTest, WritesNetwork2ToTimingExtension) {
RtpRtcpInterface::Configuration rtp_config = DefaultConfig();
rtp_config.populate_network2_timestamp = true;
RtpSenderEgress sender(env_, rtp_config, &packet_history_);
header_extensions_.RegisterByUri(kVideoTimingExtensionId,
VideoTimingExtension::Uri());
const uint16_t kPacerExitMs = 1234u;
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
VideoSendTiming send_timing = {};
send_timing.pacer_exit_delta_ms = kPacerExitMs;
packet->SetExtension<VideoTimingExtension>(send_timing);
const int kStoredTimeInMs = 100;
time_controller_.AdvanceTime(TimeDelta::Millis(kStoredTimeInMs));
sender.SendPacket(std::move(packet), PacedPacketInfo());
ASSERT_TRUE(transport_.last_packet().has_value());
VideoSendTiming video_timing;
EXPECT_TRUE(
transport_.last_packet()->packet.GetExtension<VideoTimingExtension>(
&video_timing));
EXPECT_EQ(video_timing.network2_timestamp_delta_ms, kStoredTimeInMs);
EXPECT_EQ(video_timing.pacer_exit_delta_ms, kPacerExitMs);
}
TEST_F(RtpSenderEgressTest, WritesTransportSequenceNumberExtensionIfAllocated) {
RtpSenderEgress sender(env_, DefaultConfig(), &packet_history_);
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
ASSERT_TRUE(packet->HasExtension<TransportSequenceNumber>());
const int64_t kTransportSequenceNumber = 0xFFFF000F;
packet->set_transport_sequence_number(kTransportSequenceNumber);
sender.SendPacket(std::move(packet), PacedPacketInfo());
ASSERT_TRUE(transport_.last_packet().has_value());
EXPECT_EQ(
transport_.last_packet()->packet.GetExtension<TransportSequenceNumber>(),
kTransportSequenceNumber & 0xFFFF);
}
TEST_F(RtpSenderEgressTest, OnSendPacketUpdated) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
const uint16_t kTransportSequenceNumber = 1;
EXPECT_CALL(send_packet_observer_,
OnSendPacket(Eq(kTransportSequenceNumber),
env_.clock().CurrentTime(), kSsrc));
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(kTransportSequenceNumber);
sender->SendPacket(std::move(packet), PacedPacketInfo());
}
TEST_F(RtpSenderEgressTest, OnSendPacketUpdatedWithoutTransportSequenceNumber) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
EXPECT_CALL(
send_packet_observer_,
OnSendPacket(Eq(std::nullopt), env_.clock().CurrentTime(), kSsrc));
sender->SendPacket(BuildRtpPacket(), PacedPacketInfo());
}
TEST_F(RtpSenderEgressTest, OnSendPacketNotUpdatedForRetransmits) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
const uint16_t kTransportSequenceNumber = 1;
EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(0);
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(kTransportSequenceNumber);
packet->set_packet_type(RtpPacketMediaType::kRetransmission);
packet->set_retransmitted_sequence_number(packet->SequenceNumber());
packet->set_original_ssrc(packet->Ssrc());
sender->SendPacket(std::move(packet), PacedPacketInfo());
}
TEST_F(RtpSenderEgressTest, ReportsFecRate) {
constexpr int kNumPackets = 10;
constexpr TimeDelta kTimeBetweenPackets = TimeDelta::Millis(33);
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
DataSize total_fec_data_sent = DataSize::Zero();
// Send some packets, alternating between media and FEC.
for (size_t i = 0; i < kNumPackets; ++i) {
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
media_packet->set_packet_type(RtpPacketMediaType::kVideo);
media_packet->SetPayloadSize(500);
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
std::unique_ptr<RtpPacketToSend> fec_packet = BuildRtpPacket();
fec_packet->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
fec_packet->SetPayloadSize(123);
auto fec_packet_size = fec_packet->size();
sender->SendPacket(std::move(fec_packet), PacedPacketInfo());
total_fec_data_sent += DataSize::Bytes(fec_packet_size);
time_controller_.AdvanceTime(kTimeBetweenPackets);
}
EXPECT_NEAR(
(sender->GetSendRates(
time_controller_.GetClock()
->CurrentTime())[RtpPacketMediaType::kForwardErrorCorrection])
.bps(),
(total_fec_data_sent / (kTimeBetweenPackets * kNumPackets)).bps(), 500);
}
TEST_F(RtpSenderEgressTest, BitrateCallbacks) {
class MockBitrateStaticsObserver : public BitrateStatisticsObserver {
public:
MOCK_METHOD(void, Notify, (uint32_t, uint32_t, uint32_t), (override));
} observer;
RtpRtcpInterface::Configuration config = DefaultConfig();
config.send_bitrate_observer = &observer;
RtpSenderEgress sender(env_, config, &packet_history_);
// Simulate kNumPackets sent with kPacketInterval intervals, with the
// number of packets selected so that we fill (but don't overflow) the one
// second averaging window.
const TimeDelta kWindowSize = TimeDelta::Seconds(1);
const TimeDelta kPacketInterval = TimeDelta::Millis(20);
const int kNumPackets = (kWindowSize - kPacketInterval) / kPacketInterval;
DataSize total_data_sent = DataSize::Zero();
// Send all but on of the packets, expect a call for each packet but don't
// verify bitrate yet (noisy measurements in the beginning).
for (int i = 0; i < kNumPackets; ++i) {
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->SetPayloadSize(500);
// Mark all packets as retransmissions - will cause total and retransmission
// rates to be equal.
packet->set_packet_type(RtpPacketMediaType::kRetransmission);
packet->set_retransmitted_sequence_number(packet->SequenceNumber());
total_data_sent += DataSize::Bytes(packet->size());
EXPECT_CALL(observer, Notify(_, _, kSsrc))
.WillOnce([&](uint32_t total_bitrate_bps,
uint32_t retransmission_bitrate_bps, uint32_t /*ssrc*/) {
TimeDelta window_size = i * kPacketInterval + TimeDelta::Millis(1);
// If there is just a single data point, there is no well defined
// averaging window so a bitrate of zero will be reported.
const double expected_bitrate_bps =
i == 0 ? 0.0 : (total_data_sent / window_size).bps();
EXPECT_NEAR(total_bitrate_bps, expected_bitrate_bps, 500);
EXPECT_NEAR(retransmission_bitrate_bps, expected_bitrate_bps, 500);
});
sender.SendPacket(std::move(packet), PacedPacketInfo());
time_controller_.AdvanceTime(kPacketInterval);
}
}
TEST_F(RtpSenderEgressTest, DoesNotPutNotRetransmittablePacketsInHistory) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
packet_history_.SetStorePacketsStatus(
RtpPacketHistory::StorageMode::kStoreAndCull, 10);
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_allow_retransmission(false);
auto packet_sequence_number = packet->SequenceNumber();
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_FALSE(packet_history_.GetPacketState(packet_sequence_number));
}
TEST_F(RtpSenderEgressTest, PutsRetransmittablePacketsInHistory) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
packet_history_.SetStorePacketsStatus(
RtpPacketHistory::StorageMode::kStoreAndCull, 10);
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_allow_retransmission(true);
auto packet_sequence_number = packet->SequenceNumber();
sender->SendPacket(std::move(packet), PacedPacketInfo());
EXPECT_TRUE(packet_history_.GetPacketState(packet_sequence_number));
}
TEST_F(RtpSenderEgressTest, DoesNotPutNonMediaInHistory) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
packet_history_.SetStorePacketsStatus(
RtpPacketHistory::StorageMode::kStoreAndCull, 10);
// Non-media packets, even when marked as retransmittable, are not put into
// the packet history.
std::unique_ptr<RtpPacketToSend> retransmission = BuildRtpPacket();
retransmission->set_allow_retransmission(true);
retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
retransmission->set_retransmitted_sequence_number(
retransmission->SequenceNumber());
auto retransmission_sequence_number = retransmission->SequenceNumber();
sender->SendPacket(std::move(retransmission), PacedPacketInfo());
EXPECT_FALSE(packet_history_.GetPacketState(retransmission_sequence_number));
std::unique_ptr<RtpPacketToSend> fec = BuildRtpPacket();
fec->set_allow_retransmission(true);
fec->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
auto fec_sequence_number = fec->SequenceNumber();
sender->SendPacket(std::move(fec), PacedPacketInfo());
EXPECT_FALSE(packet_history_.GetPacketState(fec_sequence_number));
std::unique_ptr<RtpPacketToSend> padding = BuildRtpPacket();
padding->set_allow_retransmission(true);
padding->set_packet_type(RtpPacketMediaType::kPadding);
auto padding_sequence_number = padding->SequenceNumber();
sender->SendPacket(std::move(padding), PacedPacketInfo());
EXPECT_FALSE(packet_history_.GetPacketState(padding_sequence_number));
}
TEST_F(RtpSenderEgressTest, UpdatesSendStatusOfRetransmittedPackets) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
packet_history_.SetStorePacketsStatus(
RtpPacketHistory::StorageMode::kStoreAndCull, 10);
// Send a packet, putting it in the history.
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
media_packet->set_allow_retransmission(true);
auto media_packet_sequence_number = media_packet->SequenceNumber();
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
EXPECT_TRUE(packet_history_.GetPacketState(media_packet_sequence_number));
// Simulate a retransmission, marking the packet as pending.
std::unique_ptr<RtpPacketToSend> retransmission =
packet_history_.GetPacketAndMarkAsPending(media_packet_sequence_number);
retransmission->set_retransmitted_sequence_number(
media_packet_sequence_number);
retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
EXPECT_TRUE(packet_history_.GetPacketState(media_packet_sequence_number));
// Simulate packet leaving pacer, the packet should be marked as non-pending.
sender->SendPacket(std::move(retransmission), PacedPacketInfo());
EXPECT_TRUE(packet_history_.GetPacketState(media_packet_sequence_number));
}
TEST_F(RtpSenderEgressTest, StreamDataCountersCallbacks) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
const RtpPacketCounter kEmptyCounter;
RtpPacketCounter expected_transmitted_counter;
RtpPacketCounter expected_retransmission_counter;
// Send a media packet.
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
media_packet->SetPayloadSize(6);
media_packet->SetSequenceNumber(kStartSequenceNumber);
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
media_packet->set_time_in_send_queue(TimeDelta::Millis(10));
expected_transmitted_counter.packets += 1;
expected_transmitted_counter.payload_bytes += media_packet->payload_size();
expected_transmitted_counter.header_bytes += media_packet->headers_size();
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
expected_transmitted_counter.total_packet_delay += TimeDelta::Millis(10);
EXPECT_CALL(
mock_rtp_stats_callback_,
DataCountersUpdated(AllOf(Field(&StreamDataCounters::transmitted,
expected_transmitted_counter),
Field(&StreamDataCounters::retransmitted,
expected_retransmission_counter),
Field(&StreamDataCounters::fec, kEmptyCounter)),
kSsrc));
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
// Send a retransmission. Retransmissions are counted into both transmitted
// and retransmitted packet statistics.
std::unique_ptr<RtpPacketToSend> retransmission_packet = BuildRtpPacket();
retransmission_packet->set_packet_type(RtpPacketMediaType::kRetransmission);
retransmission_packet->SetSequenceNumber(kStartSequenceNumber);
retransmission_packet->set_retransmitted_sequence_number(
kStartSequenceNumber);
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
retransmission_packet->set_time_in_send_queue(TimeDelta::Millis(20));
expected_transmitted_counter.packets += 1;
expected_transmitted_counter.payload_bytes +=
retransmission_packet->payload_size();
expected_transmitted_counter.header_bytes +=
retransmission_packet->headers_size();
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
expected_transmitted_counter.total_packet_delay += TimeDelta::Millis(20);
expected_retransmission_counter.packets += 1;
expected_retransmission_counter.payload_bytes +=
retransmission_packet->payload_size();
expected_retransmission_counter.header_bytes +=
retransmission_packet->headers_size();
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
expected_retransmission_counter.total_packet_delay += TimeDelta::Millis(20);
EXPECT_CALL(
mock_rtp_stats_callback_,
DataCountersUpdated(AllOf(Field(&StreamDataCounters::transmitted,
expected_transmitted_counter),
Field(&StreamDataCounters::retransmitted,
expected_retransmission_counter),
Field(&StreamDataCounters::fec, kEmptyCounter)),
kSsrc));
sender->SendPacket(std::move(retransmission_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
// Send a padding packet.
std::unique_ptr<RtpPacketToSend> padding_packet = BuildRtpPacket();
padding_packet->set_packet_type(RtpPacketMediaType::kPadding);
padding_packet->SetPadding(224);
padding_packet->SetSequenceNumber(kStartSequenceNumber + 1);
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
padding_packet->set_time_in_send_queue(TimeDelta::Millis(30));
expected_transmitted_counter.packets += 1;
expected_transmitted_counter.padding_bytes += padding_packet->padding_size();
expected_transmitted_counter.header_bytes += padding_packet->headers_size();
[Stats] Update totalPacketSendDelay to only cover time in pacer queue. This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38480}
2022-10-26 16:50:53 +02:00
expected_transmitted_counter.total_packet_delay += TimeDelta::Millis(30);
EXPECT_CALL(
mock_rtp_stats_callback_,
DataCountersUpdated(AllOf(Field(&StreamDataCounters::transmitted,
expected_transmitted_counter),
Field(&StreamDataCounters::retransmitted,
expected_retransmission_counter),
Field(&StreamDataCounters::fec, kEmptyCounter)),
kSsrc));
sender->SendPacket(std::move(padding_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
}
TEST_F(RtpSenderEgressTest, StreamDataCountersCallbacksFec) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
const RtpPacketCounter kEmptyCounter;
RtpPacketCounter expected_transmitted_counter;
RtpPacketCounter expected_fec_counter;
// Send a media packet.
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
media_packet->SetPayloadSize(6);
expected_transmitted_counter.packets += 1;
expected_transmitted_counter.payload_bytes += media_packet->payload_size();
expected_transmitted_counter.header_bytes += media_packet->headers_size();
EXPECT_CALL(
mock_rtp_stats_callback_,
DataCountersUpdated(
AllOf(Field(&StreamDataCounters::transmitted,
expected_transmitted_counter),
Field(&StreamDataCounters::retransmitted, kEmptyCounter),
Field(&StreamDataCounters::fec, expected_fec_counter)),
kSsrc));
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
// Send and FEC packet. FEC is counted into both transmitted and FEC packet
// statistics.
std::unique_ptr<RtpPacketToSend> fec_packet = BuildRtpPacket();
fec_packet->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
fec_packet->SetPayloadSize(6);
expected_transmitted_counter.packets += 1;
expected_transmitted_counter.payload_bytes += fec_packet->payload_size();
expected_transmitted_counter.header_bytes += fec_packet->headers_size();
expected_fec_counter.packets += 1;
expected_fec_counter.payload_bytes += fec_packet->payload_size();
expected_fec_counter.header_bytes += fec_packet->headers_size();
EXPECT_CALL(
mock_rtp_stats_callback_,
DataCountersUpdated(
AllOf(Field(&StreamDataCounters::transmitted,
expected_transmitted_counter),
Field(&StreamDataCounters::retransmitted, kEmptyCounter),
Field(&StreamDataCounters::fec, expected_fec_counter)),
kSsrc));
sender->SendPacket(std::move(fec_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
}
TEST_F(RtpSenderEgressTest, UpdatesDataCounters) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
const RtpPacketCounter kEmptyCounter;
// Send a media packet.
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
media_packet->SetPayloadSize(6);
auto media_packet_sequence_number = media_packet->SequenceNumber();
auto media_packet_payload_size = media_packet->payload_size();
auto media_packet_padding_size = media_packet->padding_size();
auto media_packet_headers_size = media_packet->headers_size();
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
// Send an RTX retransmission packet.
std::unique_ptr<RtpPacketToSend> rtx_packet = BuildRtpPacket();
rtx_packet->set_packet_type(RtpPacketMediaType::kRetransmission);
rtx_packet->SetSsrc(kRtxSsrc);
rtx_packet->SetPayloadSize(7);
rtx_packet->set_retransmitted_sequence_number(media_packet_sequence_number);
auto rtx_packet_payload_size = rtx_packet->payload_size();
auto rtx_packet_padding_size = rtx_packet->padding_size();
auto rtx_packet_headers_size = rtx_packet->headers_size();
sender->SendPacket(std::move(rtx_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
StreamDataCounters rtp_stats;
StreamDataCounters rtx_stats;
sender->GetDataCounters(&rtp_stats, &rtx_stats);
EXPECT_EQ(rtp_stats.transmitted.packets, 1u);
EXPECT_EQ(rtp_stats.transmitted.payload_bytes, media_packet_payload_size);
EXPECT_EQ(rtp_stats.transmitted.padding_bytes, media_packet_padding_size);
EXPECT_EQ(rtp_stats.transmitted.header_bytes, media_packet_headers_size);
EXPECT_EQ(rtp_stats.retransmitted, kEmptyCounter);
EXPECT_EQ(rtp_stats.fec, kEmptyCounter);
// Retransmissions are counted both into transmitted and retransmitted
// packet counts.
EXPECT_EQ(rtx_stats.transmitted.packets, 1u);
EXPECT_EQ(rtx_stats.transmitted.payload_bytes, rtx_packet_payload_size);
EXPECT_EQ(rtx_stats.transmitted.padding_bytes, rtx_packet_padding_size);
EXPECT_EQ(rtx_stats.transmitted.header_bytes, rtx_packet_headers_size);
EXPECT_EQ(rtx_stats.retransmitted, rtx_stats.transmitted);
EXPECT_EQ(rtx_stats.fec, kEmptyCounter);
}
TEST_F(RtpSenderEgressTest, SendPacketUpdatesExtensions) {
header_extensions_.RegisterByUri(kVideoTimingExtensionId,
VideoTimingExtension::Uri());
header_extensions_.RegisterByUri(kAbsoluteSendTimeExtensionId,
AbsoluteSendTime::Uri());
header_extensions_.RegisterByUri(kTransmissionOffsetExtensionId,
TransmissionOffset::Uri());
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_packetization_finish_time(env_.clock().CurrentTime());
const int32_t kDiffMs = 10;
time_controller_.AdvanceTime(TimeDelta::Millis(kDiffMs));
sender->SendPacket(std::move(packet), PacedPacketInfo());
RtpPacketReceived received_packet = transport_.last_packet()->packet;
EXPECT_EQ(received_packet.GetExtension<TransmissionOffset>(), kDiffMs * 90);
EXPECT_EQ(received_packet.GetExtension<AbsoluteSendTime>(),
AbsoluteSendTime::To24Bits(env_.clock().CurrentTime()));
VideoSendTiming timing;
EXPECT_TRUE(received_packet.GetExtension<VideoTimingExtension>(&timing));
EXPECT_EQ(timing.pacer_exit_delta_ms, kDiffMs);
}
TEST_F(RtpSenderEgressTest, SendPacketSetsPacketOptions) {
const uint16_t kPacketId = 42;
const uint16_t kSequenceNumber = 456;
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
uint32_t ssrc = packet->Ssrc();
packet->SetSequenceNumber(kSequenceNumber);
packet->set_transport_sequence_number(kPacketId);
EXPECT_CALL(send_packet_observer_, OnSendPacket);
sender->SendPacket(std::move(packet), PacedPacketInfo());
PacketOptions packet_options = transport_.last_packet()->options;
EXPECT_EQ(packet_options.packet_id, kPacketId);
EXPECT_TRUE(packet_options.included_in_allocation);
EXPECT_TRUE(packet_options.included_in_feedback);
EXPECT_FALSE(packet_options.is_retransmit);
// Send another packet as retransmission, verify options are populated.
std::unique_ptr<RtpPacketToSend> retransmission = BuildRtpPacket();
retransmission->set_transport_sequence_number(kPacketId + 1);
retransmission->set_packet_type(RtpPacketMediaType::kRetransmission);
retransmission->set_retransmitted_sequence_number(kSequenceNumber);
retransmission->set_original_ssrc(ssrc);
sender->SendPacket(std::move(retransmission), PacedPacketInfo());
EXPECT_TRUE(transport_.last_packet()->options.is_retransmit);
}
TEST_F(RtpSenderEgressTest, SendPacketSetsPacketOptionsIdFromExtension) {
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
RtpSenderEgress sender(env_, DefaultConfig(), &packet_history_);
// 64-bit transport sequence number.
const int64_t kTransportSequenceNumber = 0xFFFF000F;
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(kTransportSequenceNumber);
EXPECT_CALL(send_packet_observer_, OnSendPacket);
sender.SendPacket(std::move(packet), PacedPacketInfo());
ASSERT_TRUE(transport_.last_packet().has_value());
EXPECT_EQ(
transport_.last_packet()->packet.GetExtension<TransportSequenceNumber>(),
kTransportSequenceNumber & 0xFFFF);
PacketOptions packet_options = transport_.last_packet()->options;
// 16 bit packet id.
EXPECT_EQ(packet_options.packet_id, kTransportSequenceNumber & 0xFFFF);
}
TEST_F(RtpSenderEgressTest,
SendPacketSetsPacketOptionsIdFromRtpSendPacketIfNotUsingExtension) {
RtpSenderEgress sender(env_, DefaultConfig(), &packet_history_);
// 64-bit transport sequence number.
const int64_t kTransportSequenceNumber = 0xFFFF000F;
std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket();
packet->set_transport_sequence_number(kTransportSequenceNumber);
EXPECT_CALL(send_packet_observer_, OnSendPacket);
sender.SendPacket(std::move(packet), PacedPacketInfo());
ASSERT_TRUE(transport_.last_packet().has_value());
ASSERT_FALSE(
transport_.last_packet()->packet.HasExtension<TransportSequenceNumber>());
PacketOptions packet_options = transport_.last_packet()->options;
EXPECT_EQ(packet_options.packet_id, kTransportSequenceNumber);
}
TEST_F(RtpSenderEgressTest, SendPacketUpdatesStats) {
const size_t kPayloadSize = 1000;
const rtc::ArrayView<const RtpExtensionSize> kNoRtpHeaderExtensionSizes;
FlexfecSender flexfec(env_, kFlexfectPayloadType, kFlexFecSsrc, kSsrc,
/*mid=*/"",
/*header_extensions=*/{}, kNoRtpHeaderExtensionSizes,
/*rtp_state=*/nullptr);
RtpRtcpInterface::Configuration config = DefaultConfig();
config.fec_generator = &flexfec;
RtpSenderEgress sender(env_, config, &packet_history_);
header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId,
TransportSequenceNumber::Uri());
const Timestamp capture_time = env_.clock().CurrentTime();
std::unique_ptr<RtpPacketToSend> video_packet = BuildRtpPacket();
video_packet->set_packet_type(RtpPacketMediaType::kVideo);
video_packet->SetPayloadSize(kPayloadSize);
video_packet->set_transport_sequence_number(1);
std::unique_ptr<RtpPacketToSend> rtx_packet = BuildRtpPacket();
rtx_packet->SetSsrc(kRtxSsrc);
rtx_packet->set_packet_type(RtpPacketMediaType::kRetransmission);
rtx_packet->set_original_ssrc(video_packet->Ssrc());
rtx_packet->set_retransmitted_sequence_number(video_packet->SequenceNumber());
rtx_packet->SetPayloadSize(kPayloadSize);
rtx_packet->set_transport_sequence_number(2);
std::unique_ptr<RtpPacketToSend> fec_packet = BuildRtpPacket();
fec_packet->SetSsrc(kFlexFecSsrc);
fec_packet->set_packet_type(RtpPacketMediaType::kForwardErrorCorrection);
fec_packet->SetPayloadSize(kPayloadSize);
fec_packet->set_transport_sequence_number(3);
const int64_t kDiffMs = 25;
time_controller_.AdvanceTime(TimeDelta::Millis(kDiffMs));
EXPECT_CALL(send_packet_observer_, OnSendPacket(Eq(1), capture_time, kSsrc));
sender.SendPacket(std::move(video_packet), PacedPacketInfo());
// Send packet observer not called for padding/retransmissions.
EXPECT_CALL(send_packet_observer_, OnSendPacket(Eq(2), _, _)).Times(0);
sender.SendPacket(std::move(rtx_packet), PacedPacketInfo());
EXPECT_CALL(send_packet_observer_,
OnSendPacket(Eq(3), capture_time, kFlexFecSsrc));
sender.SendPacket(std::move(fec_packet), PacedPacketInfo());
time_controller_.AdvanceTime(TimeDelta::Zero());
StreamDataCounters rtp_stats;
StreamDataCounters rtx_stats;
sender.GetDataCounters(&rtp_stats, &rtx_stats);
EXPECT_EQ(rtp_stats.transmitted.packets, 2u);
EXPECT_EQ(rtp_stats.fec.packets, 1u);
EXPECT_EQ(rtx_stats.retransmitted.packets, 1u);
}
TEST_F(RtpSenderEgressTest, SupportsAbortingRetransmissions) {
std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress();
packet_history_.SetStorePacketsStatus(
RtpPacketHistory::StorageMode::kStoreAndCull, 10);
// Create a packet and send it so it is put in the history.
std::unique_ptr<RtpPacketToSend> media_packet = BuildRtpPacket();
media_packet->set_packet_type(RtpPacketMediaType::kVideo);
media_packet->set_allow_retransmission(true);
const uint16_t media_sequence_number = media_packet->SequenceNumber();
sender->SendPacket(std::move(media_packet), PacedPacketInfo());
// Fetch a retranmission packet from the history, this should mark the
// media packets as pending so it is not available to grab again.
std::unique_ptr<RtpPacketToSend> retransmission_packet =
packet_history_.GetPacketAndMarkAsPending(media_sequence_number);
ASSERT_TRUE(retransmission_packet);
EXPECT_FALSE(
packet_history_.GetPacketAndMarkAsPending(media_sequence_number));
// Mark retransmission as aborted, fetching packet is possible again.
retransmission_packet.reset();
uint16_t kAbortedSequenceNumbers[] = {media_sequence_number};
sender->OnAbortedRetransmissions(kAbortedSequenceNumbers);
EXPECT_TRUE(packet_history_.GetPacketAndMarkAsPending(media_sequence_number));
}
} // namespace webrtc