1 /*
2  *  Copyright 2018 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 #ifndef CALL_SIMULATED_NETWORK_H_
11 #define CALL_SIMULATED_NETWORK_H_
12 
13 #include <stdint.h>
14 
15 #include <deque>
16 #include <queue>
17 #include <vector>
18 
19 #include "absl/types/optional.h"
20 #include "api/sequence_checker.h"
21 #include "api/test/simulated_network.h"
22 #include "api/units/data_size.h"
23 #include "api/units/timestamp.h"
24 #include "rtc_base/race_checker.h"
25 #include "rtc_base/random.h"
26 #include "rtc_base/synchronization/mutex.h"
27 #include "rtc_base/thread_annotations.h"
28 
29 namespace webrtc {
30 // Implementation of the CoDel active queue management algorithm. Loosely based
31 // on CoDel pseudocode from ACMQueue. CoDel keeps queuing delays low by dropping
32 // packets when delay is high. For each packet ready for dequeue, call
33 // DropDequeuePacket with the packet parameters to update the CoDel state.
34 class CoDelSimulation {
35  public:
36   CoDelSimulation();
37   ~CoDelSimulation();
38 
39   // Returns true if packet should be dropped.
40   bool DropDequeuedPacket(Timestamp now,
41                           Timestamp enqueing_time,
42                           DataSize packet_size,
43                           DataSize queue_size);
44 
45  private:
46   enum State { kNormal, kPending, kDropping };
47   Timestamp enter_drop_state_at_ = Timestamp::PlusInfinity();
48   Timestamp last_drop_at_ = Timestamp::MinusInfinity();
49   int drop_count_ = 0;
50   int previous_drop_count_ = 0;
51   State state_ = State::kNormal;
52 };
53 
54 // Class simulating a network link. This is a simple and naive solution just
55 // faking capacity and adding an extra transport delay in addition to the
56 // capacity introduced delay.
57 class SimulatedNetwork : public SimulatedNetworkInterface {
58  public:
59   using Config = BuiltInNetworkBehaviorConfig;
60   explicit SimulatedNetwork(Config config, uint64_t random_seed = 1);
61   ~SimulatedNetwork() override;
62 
63   // Sets a new configuration. This won't affect packets already in the pipe.
64   void SetConfig(const Config& config) override;
65   void UpdateConfig(std::function<void(BuiltInNetworkBehaviorConfig*)>
66                         config_modifier) override;
67   void PauseTransmissionUntil(int64_t until_us) override;
68 
69   // NetworkBehaviorInterface
70   bool EnqueuePacket(PacketInFlightInfo packet) override;
71   std::vector<PacketDeliveryInfo> DequeueDeliverablePackets(
72       int64_t receive_time_us) override;
73 
74   absl::optional<int64_t> NextDeliveryTimeUs() const override;
75 
76  private:
77   struct PacketInfo {
78     PacketInFlightInfo packet;
79     int64_t arrival_time_us;
80   };
81   // Contains current configuration state.
82   struct ConfigState {
83     // Static link configuration.
84     Config config;
85     // The probability to drop the packet if we are currently dropping a
86     // burst of packet
87     double prob_loss_bursting;
88     // The probability to drop a burst of packets.
89     double prob_start_bursting;
90     // Used for temporary delay spikes.
91     int64_t pause_transmission_until_us = 0;
92   };
93 
94   // Moves packets from capacity- to delay link.
95   void UpdateCapacityQueue(ConfigState state, int64_t time_now_us)
96       RTC_RUN_ON(&process_checker_);
97   ConfigState GetConfigState() const;
98 
99   mutable Mutex config_lock_;
100 
101   // |process_checker_| guards the data structures involved in delay and loss
102   // processes, such as the packet queues.
103   rtc::RaceChecker process_checker_;
104   CoDelSimulation codel_controller_ RTC_GUARDED_BY(process_checker_);
105   std::queue<PacketInfo> capacity_link_ RTC_GUARDED_BY(process_checker_);
106   Random random_;
107 
108   std::deque<PacketInfo> delay_link_ RTC_GUARDED_BY(process_checker_);
109 
110   ConfigState config_state_ RTC_GUARDED_BY(config_lock_);
111 
112   // Are we currently dropping a burst of packets?
113   bool bursting_;
114 
115   int64_t queue_size_bytes_ RTC_GUARDED_BY(process_checker_) = 0;
116   int64_t pending_drain_bits_ RTC_GUARDED_BY(process_checker_) = 0;
117   absl::optional<int64_t> last_capacity_link_visit_us_
118       RTC_GUARDED_BY(process_checker_);
119   absl::optional<int64_t> next_process_time_us_
120       RTC_GUARDED_BY(process_checker_);
121 };
122 
123 }  // namespace webrtc
124 
125 #endif  // CALL_SIMULATED_NETWORK_H_
126