1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/pacing/paced_sender.h"
12
13 #include <list>
14 #include <memory>
15 #include <string>
16 #include <utility>
17 #include <vector>
18
19 #include "modules/pacing/packet_router.h"
20 #include "modules/utility/include/mock/mock_process_thread.h"
21 #include "system_wrappers/include/clock.h"
22 #include "system_wrappers/include/field_trial.h"
23 #include "test/field_trial.h"
24 #include "test/gmock.h"
25 #include "test/gtest.h"
26
27 using ::testing::_;
28 using ::testing::Return;
29 using ::testing::SaveArg;
30
31 namespace webrtc {
32 namespace {
33 constexpr uint32_t kAudioSsrc = 12345;
34 constexpr uint32_t kVideoSsrc = 234565;
35 constexpr uint32_t kVideoRtxSsrc = 34567;
36 constexpr uint32_t kFlexFecSsrc = 45678;
37 constexpr size_t kDefaultPacketSize = 234;
38
39 // Mock callback implementing the raw api.
40 class MockCallback : public PacketRouter {
41 public:
42 MOCK_METHOD(void,
43 SendPacket,
44 (std::unique_ptr<RtpPacketToSend> packet,
45 const PacedPacketInfo& cluster_info),
46 (override));
47 MOCK_METHOD(std::vector<std::unique_ptr<RtpPacketToSend>>,
48 GeneratePadding,
49 (DataSize target_size),
50 (override));
51 };
52
53 class ProcessModeTrials : public WebRtcKeyValueConfig {
54 public:
ProcessModeTrials(bool dynamic_process)55 explicit ProcessModeTrials(bool dynamic_process) : mode_(dynamic_process) {}
56
Lookup(absl::string_view key) const57 std::string Lookup(absl::string_view key) const override {
58 if (key == "WebRTC-Pacer-DynamicProcess") {
59 return mode_ ? "Enabled" : "Disabled";
60 }
61 return "";
62 }
63
64 private:
65 const bool mode_;
66 };
67 } // namespace
68
69 namespace test {
70
71 class PacedSenderTest
72 : public ::testing::TestWithParam<PacingController::ProcessMode> {
73 public:
PacedSenderTest()74 PacedSenderTest()
75 : clock_(0),
76 paced_module_(nullptr),
77 trials_(GetParam() == PacingController::ProcessMode::kDynamic) {}
78
SetUp()79 void SetUp() override {
80 EXPECT_CALL(process_thread_, RegisterModule)
81 .WillOnce(SaveArg<0>(&paced_module_));
82
83 pacer_ = std::make_unique<PacedSender>(&clock_, &callback_, nullptr,
84 &trials_, &process_thread_);
85 EXPECT_CALL(process_thread_, WakeUp).WillRepeatedly([&](Module* module) {
86 clock_.AdvanceTimeMilliseconds(module->TimeUntilNextProcess());
87 });
88 EXPECT_CALL(process_thread_, DeRegisterModule(paced_module_)).Times(1);
89 }
90
91 protected:
BuildRtpPacket(RtpPacketMediaType type)92 std::unique_ptr<RtpPacketToSend> BuildRtpPacket(RtpPacketMediaType type) {
93 auto packet = std::make_unique<RtpPacketToSend>(nullptr);
94 packet->set_packet_type(type);
95 switch (type) {
96 case RtpPacketMediaType::kAudio:
97 packet->SetSsrc(kAudioSsrc);
98 break;
99 case RtpPacketMediaType::kVideo:
100 packet->SetSsrc(kVideoSsrc);
101 break;
102 case RtpPacketMediaType::kRetransmission:
103 case RtpPacketMediaType::kPadding:
104 packet->SetSsrc(kVideoRtxSsrc);
105 break;
106 case RtpPacketMediaType::kForwardErrorCorrection:
107 packet->SetSsrc(kFlexFecSsrc);
108 break;
109 }
110
111 packet->SetPayloadSize(kDefaultPacketSize);
112 return packet;
113 }
114
115 SimulatedClock clock_;
116 MockCallback callback_;
117 MockProcessThread process_thread_;
118 Module* paced_module_;
119 ProcessModeTrials trials_;
120 std::unique_ptr<PacedSender> pacer_;
121 };
122
TEST_P(PacedSenderTest,PacesPackets)123 TEST_P(PacedSenderTest, PacesPackets) {
124 // Insert a number of packets, covering one second.
125 static constexpr size_t kPacketsToSend = 42;
126 pacer_->SetPacingRates(
127 DataRate::BitsPerSec(kDefaultPacketSize * 8 * kPacketsToSend),
128 DataRate::Zero());
129 std::vector<std::unique_ptr<RtpPacketToSend>> packets;
130 for (size_t i = 0; i < kPacketsToSend; ++i) {
131 packets.emplace_back(BuildRtpPacket(RtpPacketMediaType::kVideo));
132 }
133 pacer_->EnqueuePackets(std::move(packets));
134
135 // Expect all of them to be sent.
136 size_t packets_sent = 0;
137 EXPECT_CALL(callback_, SendPacket)
138 .WillRepeatedly(
139 [&](std::unique_ptr<RtpPacketToSend> packet,
140 const PacedPacketInfo& cluster_info) { ++packets_sent; });
141
142 const Timestamp start_time = clock_.CurrentTime();
143
144 while (packets_sent < kPacketsToSend) {
145 clock_.AdvanceTimeMilliseconds(paced_module_->TimeUntilNextProcess());
146 paced_module_->Process();
147 }
148
149 // Packets should be sent over a period of close to 1s. Expect a little lower
150 // than this since initial probing is a bit quicker.
151 TimeDelta duration = clock_.CurrentTime() - start_time;
152 EXPECT_GT(duration, TimeDelta::Millis(900));
153 }
154
155 INSTANTIATE_TEST_SUITE_P(
156 WithAndWithoutDynamicProcess,
157 PacedSenderTest,
158 ::testing::Values(PacingController::ProcessMode::kPeriodic,
159 PacingController::ProcessMode::kDynamic));
160
161 } // namespace test
162 } // namespace webrtc
163