summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/call/fake_network_pipe.h
blob: be72e9163713b44698a5f67b129bf1bc1e5cd6c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/*
 *  Copyright (c) 2012 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.
 */

#ifndef CALL_FAKE_NETWORK_PIPE_H_
#define CALL_FAKE_NETWORK_PIPE_H_

#include <deque>
#include <map>
#include <memory>
#include <queue>
#include <set>
#include <string>
#include <vector>

#include "api/call/transport.h"
#include "api/test/simulated_network.h"
#include "call/call.h"
#include "call/simulated_packet_receiver.h"
#include "rtc_base/synchronization/mutex.h"
#include "rtc_base/thread_annotations.h"

namespace webrtc {

class Clock;
class PacketReceiver;
enum class MediaType;

class NetworkPacket {
 public:
  NetworkPacket(rtc::CopyOnWriteBuffer packet,
                int64_t send_time,
                int64_t arrival_time,
                absl::optional<PacketOptions> packet_options,
                bool is_rtcp,
                MediaType media_type,
                absl::optional<int64_t> packet_time_us,
                Transport* transport);

  // Disallow copy constructor and copy assignment (no deep copies of `data_`).
  NetworkPacket(const NetworkPacket&) = delete;
  ~NetworkPacket();
  NetworkPacket& operator=(const NetworkPacket&) = delete;
  // Allow move constructor/assignment, so that we can use in stl containers.
  NetworkPacket(NetworkPacket&&);
  NetworkPacket& operator=(NetworkPacket&&);

  const uint8_t* data() const { return packet_.data(); }
  size_t data_length() const { return packet_.size(); }
  rtc::CopyOnWriteBuffer* raw_packet() { return &packet_; }
  int64_t send_time() const { return send_time_; }
  int64_t arrival_time() const { return arrival_time_; }
  void IncrementArrivalTime(int64_t extra_delay) {
    arrival_time_ += extra_delay;
  }
  PacketOptions packet_options() const {
    return packet_options_.value_or(PacketOptions());
  }
  bool is_rtcp() const { return is_rtcp_; }
  MediaType media_type() const { return media_type_; }
  absl::optional<int64_t> packet_time_us() const { return packet_time_us_; }
  Transport* transport() const { return transport_; }

 private:
  rtc::CopyOnWriteBuffer packet_;
  // The time the packet was sent out on the network.
  int64_t send_time_;
  // The time the packet should arrive at the receiver.
  int64_t arrival_time_;
  // If using a Transport for outgoing degradation, populate with
  // PacketOptions (transport-wide sequence number) for RTP.
  absl::optional<PacketOptions> packet_options_;
  bool is_rtcp_;
  // If using a PacketReceiver for incoming degradation, populate with
  // appropriate MediaType and packet time. This type/timing will be kept and
  // forwarded. The packet time might be altered to reflect time spent in fake
  // network pipe.
  MediaType media_type_;
  absl::optional<int64_t> packet_time_us_;
  Transport* transport_;
};

// Class faking a network link, internally is uses an implementation of a
// SimulatedNetworkInterface to simulate network behavior.
class FakeNetworkPipe : public SimulatedPacketReceiverInterface {
 public:
  // Will keep `network_behavior` alive while pipe is alive itself.
  FakeNetworkPipe(Clock* clock,
                  std::unique_ptr<NetworkBehaviorInterface> network_behavior);
  FakeNetworkPipe(Clock* clock,
                  std::unique_ptr<NetworkBehaviorInterface> network_behavior,
                  PacketReceiver* receiver);
  FakeNetworkPipe(Clock* clock,
                  std::unique_ptr<NetworkBehaviorInterface> network_behavior,
                  PacketReceiver* receiver,
                  uint64_t seed);

  // Use this constructor if you plan to insert packets using SendRt[c?]p().
  FakeNetworkPipe(Clock* clock,
                  std::unique_ptr<NetworkBehaviorInterface> network_behavior,
                  Transport* transport);

  ~FakeNetworkPipe() override;

  FakeNetworkPipe(const FakeNetworkPipe&) = delete;
  FakeNetworkPipe& operator=(const FakeNetworkPipe&) = delete;

  void SetClockOffset(int64_t offset_ms);

  // Must not be called in parallel with DeliverPacket or Process.
  void SetReceiver(PacketReceiver* receiver) override;

  // Adds/subtracts references to Transport instances. If a Transport is
  // destroyed we cannot use to forward a potential delayed packet, these
  // methods are used to maintain a map of which instances are live.
  void AddActiveTransport(Transport* transport);
  void RemoveActiveTransport(Transport* transport);

  // Implements Transport interface. When/if packets are delivered, they will
  // be passed to the transport instance given in SetReceiverTransport(). These
  // methods should only be called if a Transport instance was provided in the
  // constructor.
  bool SendRtp(const uint8_t* packet,
               size_t length,
               const PacketOptions& options);
  bool SendRtcp(const uint8_t* packet, size_t length);

  // Methods for use with Transport interface. When/if packets are delivered,
  // they will be passed to the instance specified by the `transport` parameter.
  // Note that that instance must be in the map of active transports.
  bool SendRtp(const uint8_t* packet,
               size_t length,
               const PacketOptions& options,
               Transport* transport);
  bool SendRtcp(const uint8_t* packet, size_t length, Transport* transport);

  // Implements the PacketReceiver interface. When/if packets are delivered,
  // they will be passed directly to the receiver instance given in
  // SetReceiver(), without passing through a Demuxer. The receive time
  // will be increased by the amount of time the packet spent in the
  // fake network pipe.
  PacketReceiver::DeliveryStatus DeliverPacket(MediaType media_type,
                                               rtc::CopyOnWriteBuffer packet,
                                               int64_t packet_time_us) override;

  // TODO(bugs.webrtc.org/9584): Needed to inherit the alternative signature for
  // this method.
  using PacketReceiver::DeliverPacket;

  // Processes the network queues and trigger PacketReceiver::IncomingPacket for
  // packets ready to be delivered.
  void Process() override;
  absl::optional<int64_t> TimeUntilNextProcess() override;

  // Get statistics.
  float PercentageLoss();
  int AverageDelay() override;
  size_t DroppedPackets();
  size_t SentPackets();
  void ResetStats();

 protected:
  void DeliverPacketWithLock(NetworkPacket* packet);
  int64_t GetTimeInMicroseconds() const;
  bool ShouldProcess(int64_t time_now_us) const;
  void SetTimeToNextProcess(int64_t skip_us);

 private:
  struct StoredPacket {
    NetworkPacket packet;
    bool removed = false;
    explicit StoredPacket(NetworkPacket&& packet);
    StoredPacket(StoredPacket&&) = default;
    StoredPacket(const StoredPacket&) = delete;
    StoredPacket& operator=(const StoredPacket&) = delete;
    StoredPacket() = delete;
  };

  // Returns true if enqueued, or false if packet was dropped. Use this method
  // when enqueueing packets that should be received by PacketReceiver instance.
  bool EnqueuePacket(rtc::CopyOnWriteBuffer packet,
                     absl::optional<PacketOptions> options,
                     bool is_rtcp,
                     MediaType media_type,
                     absl::optional<int64_t> packet_time_us);

  // Returns true if enqueued, or false if packet was dropped. Use this method
  // when enqueueing packets that should be received by Transport instance.
  bool EnqueuePacket(rtc::CopyOnWriteBuffer packet,
                     absl::optional<PacketOptions> options,
                     bool is_rtcp,
                     Transport* transport);

  bool EnqueuePacket(NetworkPacket&& net_packet)
      RTC_EXCLUSIVE_LOCKS_REQUIRED(process_lock_);

  void DeliverNetworkPacket(NetworkPacket* packet)
      RTC_EXCLUSIVE_LOCKS_REQUIRED(config_lock_);
  bool HasReceiver() const;

  Clock* const clock_;
  // `config_lock` guards the mostly constant things like the callbacks.
  mutable Mutex config_lock_;
  const std::unique_ptr<NetworkBehaviorInterface> network_behavior_;
  PacketReceiver* receiver_ RTC_GUARDED_BY(config_lock_);
  Transport* const global_transport_;

  // `process_lock` guards the data structures involved in delay and loss
  // processes, such as the packet queues.
  Mutex process_lock_;
  // Packets  are added at the back of the deque, this makes the deque ordered
  // by increasing send time. The common case when removing packets from the
  // deque is removing early packets, which will be close to the front of the
  // deque. This makes finding the packets in the deque efficient in the common
  // case.
  std::deque<StoredPacket> packets_in_flight_ RTC_GUARDED_BY(process_lock_);

  int64_t clock_offset_ms_ RTC_GUARDED_BY(config_lock_);

  // Statistics.
  size_t dropped_packets_ RTC_GUARDED_BY(process_lock_);
  size_t sent_packets_ RTC_GUARDED_BY(process_lock_);
  int64_t total_packet_delay_us_ RTC_GUARDED_BY(process_lock_);
  int64_t last_log_time_us_;

  std::map<Transport*, size_t> active_transports_ RTC_GUARDED_BY(config_lock_);
};

}  // namespace webrtc

#endif  // CALL_FAKE_NETWORK_PIPE_H_