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