* Copyright (c) 2022 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/pacing/prioritized_packet_queue.h"
#include <utility>
#include "api/units/time_delta.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "rtc_base/checks.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
constexpr uint32_t kDefaultSsrc = 123;
constexpr int kDefaultPayloadSize = 789;
std::unique_ptr<RtpPacketToSend> CreatePacket(RtpPacketMediaType type,
uint16_t sequence_number,
uint32_t ssrc = kDefaultSsrc,
bool is_key_frame = false) {
auto packet = std::make_unique<RtpPacketToSend>(nullptr);
packet->set_packet_type(type);
packet->SetSsrc(ssrc);
packet->SetSequenceNumber(sequence_number);
packet->SetPayloadSize(kDefaultPayloadSize);
packet->set_is_key_frame(is_key_frame);
return packet;
}
}
TEST(PrioritizedPacketQueue, ReturnsPacketsInPrioritizedOrder) {
Timestamp now = Timestamp::Zero();
PrioritizedPacketQueue queue(now);
queue.Push(now, CreatePacket(RtpPacketMediaType::kPadding, 1));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 2));
queue.Push(now, CreatePacket(RtpPacketMediaType::kForwardErrorCorrection,
3));
queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, 4));
queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, 5));
EXPECT_EQ(queue.Pop()->SequenceNumber(), 5);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 4);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 2);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 3);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 1);
}
TEST(PrioritizedPacketQueue, ReturnsEqualPrioPacketsInRoundRobinOrder) {
Timestamp now = Timestamp::Zero();
PrioritizedPacketQueue queue(now);
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 1, 100));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 2, 101));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 3, 101));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 4, 102));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 5, 102));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 6, 102));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 7, 102));
EXPECT_EQ(queue.Pop()->SequenceNumber(), 1);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 2);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 4);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 3);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 5);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 6);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 7);
}
TEST(PrioritizedPacketQueue, ReportsSizeInPackets) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.SizeInPackets(), 0);
queue.Push(Timestamp::Zero(),
CreatePacket(RtpPacketMediaType::kVideo,
1));
EXPECT_EQ(queue.SizeInPackets(), 1);
queue.Pop();
EXPECT_EQ(queue.SizeInPackets(), 0);
}
TEST(PrioritizedPacketQueue, ReportsPayloadSize) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.SizeInPayloadBytes(), DataSize::Zero());
queue.Push(Timestamp::Zero(),
CreatePacket(RtpPacketMediaType::kVideo,
1));
EXPECT_EQ(queue.SizeInPayloadBytes(), DataSize::Bytes(kDefaultPayloadSize));
queue.Pop();
EXPECT_EQ(queue.SizeInPayloadBytes(), DataSize::Zero());
}
TEST(PrioritizedPacketQueue, ReportsPaddingSize) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.SizeInPayloadBytes(), DataSize::Zero());
static constexpr DataSize kPaddingSize = DataSize::Bytes(190);
auto packet = std::make_unique<RtpPacketToSend>(nullptr);
packet->set_packet_type(RtpPacketMediaType::kPadding);
packet->SetSsrc(kDefaultSsrc);
packet->SetSequenceNumber(1);
packet->SetPadding(kPaddingSize.bytes());
queue.Push(Timestamp::Zero(), std::move(packet));
EXPECT_EQ(queue.SizeInPayloadBytes(), kPaddingSize);
queue.Pop();
EXPECT_EQ(queue.SizeInPayloadBytes(), DataSize::Zero());
}
TEST(PrioritizedPacketQueue, ReportsOldestEnqueueTime) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.OldestEnqueueTime(), Timestamp::MinusInfinity());
queue.Push(Timestamp::Millis(10),
CreatePacket(RtpPacketMediaType::kPadding, 1));
queue.Push(Timestamp::Millis(20),
CreatePacket(RtpPacketMediaType::kVideo, 2));
queue.Push(Timestamp::Millis(30),
CreatePacket(RtpPacketMediaType::kPadding, 3));
EXPECT_EQ(queue.OldestEnqueueTime(), Timestamp::Millis(10));
queue.Pop();
EXPECT_EQ(queue.OldestEnqueueTime(), Timestamp::Millis(10));
queue.Pop();
EXPECT_EQ(queue.OldestEnqueueTime(), Timestamp::Millis(30));
queue.Pop();
EXPECT_EQ(queue.OldestEnqueueTime(), Timestamp::MinusInfinity());
}
TEST(PrioritizedPacketQueue, ReportsAverageQueueTime) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Zero());
queue.Push(Timestamp::Millis(10),
CreatePacket(RtpPacketMediaType::kPadding, 1));
queue.Push(Timestamp::Millis(20),
CreatePacket(RtpPacketMediaType::kVideo, 2));
queue.Push(Timestamp::Millis(30),
CreatePacket(RtpPacketMediaType::kPadding, 3));
queue.UpdateAverageQueueTime(Timestamp::Millis(40));
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(20));
queue.Pop();
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(20));
queue.Pop();
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(10));
queue.Pop();
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Zero());
}
TEST(PrioritizedPacketQueue, SubtractsPusedTimeFromAverageQueueTime) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Zero());
queue.Push(Timestamp::Millis(100),
CreatePacket(RtpPacketMediaType::kPadding, 1));
queue.SetPauseState(true, Timestamp::Millis(600));
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(500));
queue.Push(Timestamp::Millis(1100),
CreatePacket(RtpPacketMediaType::kVideo, 2));
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(250));
queue.SetPauseState(false, Timestamp::Millis(1600));
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(250));
queue.UpdateAverageQueueTime(Timestamp::Millis(2100));
EXPECT_EQ(queue.AverageQueueTime(), TimeDelta::Millis(750));
}
TEST(PrioritizedPacketQueue, ReportsLeadingPacketEnqueueTime) {
PrioritizedPacketQueue queue(Timestamp::Zero());
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kAudio),
Timestamp::MinusInfinity());
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kVideo),
Timestamp::MinusInfinity());
queue.Push(Timestamp::Millis(10),
CreatePacket(RtpPacketMediaType::kVideo, 1));
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kAudio),
Timestamp::MinusInfinity());
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kVideo),
Timestamp::Millis(10));
queue.Push(Timestamp::Millis(20),
CreatePacket(RtpPacketMediaType::kAudio, 2));
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kAudio),
Timestamp::Millis(20));
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kVideo),
Timestamp::Millis(10));
queue.Pop();
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kAudio),
Timestamp::MinusInfinity());
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kVideo),
Timestamp::Millis(10));
queue.Pop();
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kAudio),
Timestamp::MinusInfinity());
EXPECT_EQ(queue.LeadingPacketEnqueueTime(RtpPacketMediaType::kVideo),
Timestamp::MinusInfinity());
}
TEST(PrioritizedPacketQueue,
PushAndPopUpdatesSizeInPacketsPerRtpPacketMediaType) {
Timestamp now = Timestamp::Zero();
PrioritizedPacketQueue queue(now);
for (size_t i = 0; i < kNumMediaTypes; ++i) {
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[i], 0);
}
queue.Push(now, CreatePacket(RtpPacketMediaType::kAudio, 1));
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast<size_t>(
RtpPacketMediaType::kAudio)],
1);
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 2));
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast<size_t>(
RtpPacketMediaType::kVideo)],
1);
queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, 3));
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast<size_t>(
RtpPacketMediaType::kRetransmission)],
1);
queue.Push(now, CreatePacket(RtpPacketMediaType::kForwardErrorCorrection, 4));
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast<size_t>(
RtpPacketMediaType::kForwardErrorCorrection)],
1);
queue.Push(now, CreatePacket(RtpPacketMediaType::kPadding, 5));
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast<size_t>(
RtpPacketMediaType::kPadding)],
1);
for (size_t i = 0; i < kNumMediaTypes; ++i) {
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[i], 1);
}
for (size_t i = 0; i < kNumMediaTypes; ++i) {
auto popped_packet = queue.Pop();
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[static_cast<size_t>(
popped_packet->packet_type().value())],
0);
}
for (size_t i = 0; i < kNumMediaTypes; ++i) {
EXPECT_EQ(queue.SizeInPacketsPerRtpPacketMediaType()[i], 0);
}
}
TEST(PrioritizedPacketQueue, ClearsPackets) {
Timestamp now = Timestamp::Zero();
PrioritizedPacketQueue queue(now);
const uint32_t kSsrc = 1;
int sequence_number = 0;
for (size_t i = 0; i < kNumMediaTypes; ++i) {
queue.Push(now, CreatePacket(static_cast<RtpPacketMediaType>(i),
sequence_number++, kSsrc));
queue.Push(now, CreatePacket(static_cast<RtpPacketMediaType>(i),
sequence_number++, kSsrc));
}
EXPECT_EQ(queue.SizeInPackets(), 2 * int{kNumMediaTypes});
queue.RemovePacketsForSsrc(kSsrc);
EXPECT_TRUE(queue.Empty());
}
TEST(PrioritizedPacketQueue, ClearPacketsAffectsOnlySpecifiedSsrc) {
Timestamp now = Timestamp::Zero();
PrioritizedPacketQueue queue(now);
const uint32_t kRemovingSsrc = 1;
const uint32_t kStayingSsrc = 2;
queue.Push(
now, CreatePacket(RtpPacketMediaType::kAudio, 1, kRemovingSsrc));
queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, 2,
kRemovingSsrc));
queue.Push(now,
CreatePacket(RtpPacketMediaType::kVideo, 3, kStayingSsrc));
queue.Push(now, CreatePacket(RtpPacketMediaType::kRetransmission, 4,
kStayingSsrc));
EXPECT_EQ(queue.SizeInPackets(), 4);
queue.RemovePacketsForSsrc(kRemovingSsrc);
EXPECT_EQ(queue.SizeInPackets(), 2);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 4);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 3);
EXPECT_TRUE(queue.Empty());
}
TEST(PrioritizedPacketQueue, ReportsKeyframePackets) {
Timestamp now = Timestamp::Zero();
PrioritizedPacketQueue queue(now);
const uint32_t kVideoSsrc1 = 1234;
const uint32_t kVideoSsrc2 = 2345;
EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc2));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 1,
kVideoSsrc1, true));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 11,
kVideoSsrc2, false));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc2));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 2,
kVideoSsrc1, true));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 12,
kVideoSsrc2, true));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc2));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 3,
kVideoSsrc1, false));
queue.Push(now, CreatePacket(RtpPacketMediaType::kVideo, 13,
kVideoSsrc2, true));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc2));
EXPECT_EQ(queue.Pop()->SequenceNumber(), 1);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 11);
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc2));
EXPECT_EQ(queue.Pop()->SequenceNumber(), 2);
EXPECT_EQ(queue.Pop()->SequenceNumber(), 12);
EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_TRUE(queue.HasKeyframePackets(kVideoSsrc2));
queue.RemovePacketsForSsrc(kVideoSsrc2);
EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc1));
EXPECT_FALSE(queue.HasKeyframePackets(kVideoSsrc2));
}
}