| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COBALT_MEDIA_CAST_TEST_UTILITY_UDP_PROXY_H_ |
| #define COBALT_MEDIA_CAST_TEST_UTILITY_UDP_PROXY_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/macros.h" |
| #include "base/memory/linked_ptr.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/single_thread_task_runner.h" |
| #include "media/cast/net/cast_transport_config.h" |
| #include "net/base/ip_endpoint.h" |
| #include "starboard/types.h" |
| #include "third_party/mt19937ar/mt19937ar.h" |
| |
| namespace net { |
| class NetLog; |
| }; |
| |
| namespace base { |
| class TickClock; |
| }; |
| |
| namespace cobalt { |
| namespace media { |
| namespace cast { |
| namespace test { |
| |
| class PacketPipe { |
| public: |
| PacketPipe(); |
| virtual ~PacketPipe(); |
| virtual void Send(std::unique_ptr<Packet> packet) = 0; |
| // Allows injection of fake test runner for testing. |
| virtual void InitOnIOThread( |
| const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| base::TickClock* clock); |
| virtual void AppendToPipe(std::unique_ptr<PacketPipe> pipe); |
| |
| protected: |
| std::unique_ptr<PacketPipe> pipe_; |
| // Allows injection of fake task runner for testing. |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| base::TickClock* clock_; |
| }; |
| |
| // Implements a Interrupted Poisson Process for packet delivery. |
| // The process has 2 states: ON and OFF, the rate of switching between |
| // these two states are defined. |
| // When in ON state packets are sent according to a defined rate. |
| // When in OFF state packets are not sent. |
| // The rate above is the average rate of a poisson distribution. |
| class InterruptedPoissonProcess { |
| public: |
| InterruptedPoissonProcess(const std::vector<double>& average_rates, |
| double coef_burstiness, double coef_variance, |
| uint32_t rand_seed); |
| ~InterruptedPoissonProcess(); |
| |
| std::unique_ptr<PacketPipe> NewBuffer(size_t size); |
| |
| private: |
| class InternalBuffer; |
| |
| // |task_runner| is the executor of the IO thread. |
| // |clock| is the system clock. |
| void InitOnIOThread( |
| const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| base::TickClock* clock); |
| |
| base::TimeDelta NextEvent(double rate); |
| double RandDouble(); |
| void ComputeRates(); |
| void UpdateRates(); |
| void SwitchOff(); |
| void SwitchOn(); |
| void SendPacket(); |
| |
| scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| base::TickClock* clock_; |
| const std::vector<double> average_rates_; |
| const double coef_burstiness_; |
| const double coef_variance_; |
| int rate_index_; |
| |
| // The following rates are per milliseconds. |
| double send_rate_; |
| double switch_off_rate_; |
| double switch_on_rate_; |
| bool on_state_; |
| |
| std::vector<base::WeakPtr<InternalBuffer> > send_buffers_; |
| |
| // Fast pseudo random number generator. |
| MersenneTwister mt_rand_; |
| |
| base::WeakPtrFactory<InterruptedPoissonProcess> weak_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(InterruptedPoissonProcess); |
| }; |
| |
| // A UDPProxy will set up a UDP socket and bind to |local_port|. |
| // Packets send to that port will be forwarded to |destination|. |
| // Packets send from |destination| to |local_port| will be returned |
| // to whoever sent a packet to |local_port| last. (Not counting packets |
| // from |destination|.) The UDPProxy will run a separate thread to |
| // do the forwarding of packets, and will keep doing so until destroyed. |
| // You can insert delays and packet drops by supplying a PacketPipe. |
| // The PacketPipes may also be NULL if you just want to forward packets. |
| class UDPProxy { |
| public: |
| virtual ~UDPProxy() {} |
| static std::unique_ptr<UDPProxy> Create( |
| const net::IPEndPoint& local_port, const net::IPEndPoint& destination, |
| std::unique_ptr<PacketPipe> to_dest_pipe, |
| std::unique_ptr<PacketPipe> from_dest_pipe, net::NetLog* net_log); |
| }; |
| |
| // The following functions create PacketPipes which can be linked |
| // together (with AppendToPipe) and passed into UdpProxy::Create below. |
| |
| // This PacketPipe emulates a buffer of a given size. Limits our output |
| // from the buffer at a rate given by |bandwidth| (in megabits per second). |
| // Packets entering the buffer will be dropped if there is not enough |
| // room for them. |
| std::unique_ptr<PacketPipe> NewBuffer(size_t buffer_size, double bandwidth); |
| |
| // Randomly drops |drop_fraction|*100% of packets. |
| std::unique_ptr<PacketPipe> NewRandomDrop(double drop_fraction); |
| |
| // Delays each packet by |delay_seconds|. |
| std::unique_ptr<PacketPipe> NewConstantDelay(double delay_seconds); |
| |
| // Delays packets by a random amount between zero and |delay|. |
| // This PacketPipe can reorder packets. |
| std::unique_ptr<PacketPipe> NewRandomUnsortedDelay(double delay); |
| |
| // Duplicates every packet, one is transmitted immediately, |
| // one is transmitted after a random delay between |delay_min| |
| // and |delay_min + random_delay|. |
| // This PacketPipe will reorder packets. |
| std::unique_ptr<PacketPipe> NewDuplicateAndDelay(double delay_min, |
| double random_delay); |
| |
| // This PacketPipe inserts a random delay between each packet. |
| // This PacketPipe cannot re-order packets. The delay between each |
| // packet is asically |min_delay| + random( |random_delay| ) |
| // However, every now and then a delay of |big_delay| will be |
| // inserted (roughly every |seconds_between_big_delay| seconds). |
| std::unique_ptr<PacketPipe> NewRandomSortedDelay( |
| double random_delay, double big_delay, double seconds_between_big_delay); |
| |
| // This PacketPipe emulates network outages. It basically waits |
| // for 0-2*|average_work_time| seconds, then kills the network for |
| // 0-|2*average_outage_time| seconds. Then it starts over again. |
| std::unique_ptr<PacketPipe> NewNetworkGlitchPipe(double average_work_time, |
| double average_outage_time); |
| |
| // This method builds a stack of PacketPipes to emulate a reasonably |
| // good network. ~50mbit, ~3ms latency, no packet loss unless saturated. |
| std::unique_ptr<PacketPipe> GoodNetwork(); |
| |
| // This method builds a stack of PacketPipes to emulate a reasonably |
| // good wifi network. ~20mbit, 1% packet loss, ~3ms latency. |
| std::unique_ptr<PacketPipe> WifiNetwork(); |
| |
| // This method builds a stack of PacketPipes to emulate a |
| // bad wifi network. ~5mbit, 5% packet loss, ~7ms latency |
| // 40ms dropouts every ~2 seconds. Can reorder packets. |
| std::unique_ptr<PacketPipe> BadNetwork(); |
| |
| // This method builds a stack of PacketPipes to emulate a crappy wifi network. |
| // ~2mbit, 20% packet loss, ~40ms latency and packets can get reordered. |
| // 300ms drouputs every ~2 seconds. |
| std::unique_ptr<PacketPipe> EvilNetwork(); |
| |
| // Builds an Interrupted Poisson Process network simulator with default |
| // settings. It simulates a challenging interference-heavy WiFi environment |
| // of roughly 2mbits/s. |
| std::unique_ptr<InterruptedPoissonProcess> DefaultInterruptedPoissonProcess(); |
| |
| } // namespace test |
| } // namespace cast |
| } // namespace media |
| } // namespace cobalt |
| |
| #endif // COBALT_MEDIA_CAST_TEST_UTILITY_UDP_PROXY_H_ |