Add simulation of network effects to video_loopback tool.

Also add support for uniform random packet loss to the fake network pipe.

R=pbos@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/14039004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6803 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/test/fake_network_pipe.cc b/webrtc/test/fake_network_pipe.cc
index 06bf062..c88205b 100644
--- a/webrtc/test/fake_network_pipe.cc
+++ b/webrtc/test/fake_network_pipe.cc
@@ -33,6 +33,11 @@
                           sqrt(-2 * log(uniform1)) * cos(2 * kPi * uniform2));
 }
 
+static bool UniformLoss(int loss_percent) {
+  int outcome = rand() % 100;
+  return outcome < loss_percent;
+}
+
 class NetworkPacket {
  public:
   NetworkPacket(const uint8_t* data, size_t length, int64_t send_time,
@@ -159,6 +164,12 @@
       NetworkPacket* packet = capacity_link_.front();
       capacity_link_.pop();
 
+      // Packets are randomly dropped after being affected by the bottleneck.
+      if (UniformLoss(config_.loss_percent)) {
+        delete packet;
+        continue;
+      }
+
       // Add extra delay and jitter, but make sure the arrival time is not
       // earlier than the last packet in the queue.
       int extra_delay = GaussianRandom(config_.queue_delay_ms,
diff --git a/webrtc/test/fake_network_pipe.h b/webrtc/test/fake_network_pipe.h
index c741501..a9ca760 100644
--- a/webrtc/test/fake_network_pipe.h
+++ b/webrtc/test/fake_network_pipe.h
@@ -47,7 +47,7 @@
     int delay_standard_deviation_ms;
     // Link capacity in kbps.
     int link_capacity_kbps;
-    // Random packet loss. Not implemented.
+    // Random packet loss.
     int loss_percent;
   };
 
diff --git a/webrtc/video/loopback.cc b/webrtc/video/loopback.cc
index 614ef47..4ec7388 100644
--- a/webrtc/video/loopback.cc
+++ b/webrtc/video/loopback.cc
@@ -51,18 +51,58 @@
 
 DEFINE_string(codec, "VP8", "Video codec to use.");
 std::string Codec() { return static_cast<std::string>(FLAGS_codec); }
+
+DEFINE_int32(loss_percent, 0, "Percentage of packets randomly lost.");
+int LossPercent() {
+  return static_cast<int>(FLAGS_loss_percent);
+}
+
+DEFINE_int32(link_capacity,
+             0,
+             "Capacity (kbps) of the fake link. 0 means infinite.");
+int LinkCapacity() {
+  return static_cast<int>(FLAGS_link_capacity);
+}
+
+DEFINE_int32(queue_size, 0, "Size of the bottleneck link queue in packets.");
+int QueueSize() {
+  return static_cast<int>(FLAGS_queue_size);
+}
+
+DEFINE_int32(avg_propagation_delay_ms,
+             0,
+             "Average link propagation delay in ms.");
+int AvgPropagationDelayMs() {
+  return static_cast<int>(FLAGS_avg_propagation_delay_ms);
+}
+
+DEFINE_int32(std_propagation_delay_ms,
+             0,
+             "Link propagation delay standard deviation in ms.");
+int StdPropagationDelayMs() {
+  return static_cast<int>(FLAGS_std_propagation_delay_ms);
+}
 }  // namespace flags
 
 static const uint32_t kSendSsrc = 0x654321;
+static const uint32_t kSendRtxSsrc = 0x654322;
 static const uint32_t kReceiverLocalSsrc = 0x123456;
 
+static const uint8_t kRtxPayloadType = 96;
+
 void Loopback() {
   scoped_ptr<test::VideoRenderer> local_preview(test::VideoRenderer::Create(
       "Local Preview", flags::Width(), flags::Height()));
   scoped_ptr<test::VideoRenderer> loopback_video(test::VideoRenderer::Create(
       "Loopback Video", flags::Width(), flags::Height()));
 
-  test::DirectTransport transport;
+  FakeNetworkPipe::Config pipe_config;
+  pipe_config.loss_percent = flags::LossPercent();
+  pipe_config.link_capacity_kbps = flags::LinkCapacity();
+  pipe_config.queue_length_packets = flags::QueueSize();
+  pipe_config.queue_delay_ms = flags::AvgPropagationDelayMs();
+  pipe_config.delay_standard_deviation_ms = flags::StdPropagationDelayMs();
+  test::DirectTransport transport(pipe_config);
   Call::Config call_config(&transport);
   call_config.start_bitrate_bps =
       static_cast<int>(flags::StartBitrate()) * 1000;
@@ -73,6 +113,9 @@
 
   VideoSendStream::Config send_config;
   send_config.rtp.ssrcs.push_back(kSendSsrc);
+  send_config.rtp.rtx.ssrcs.push_back(kSendRtxSsrc);
+  send_config.rtp.rtx.payload_type = kRtxPayloadType;
+  send_config.rtp.nack.rtp_history_ms = 1000;
 
   send_config.local_renderer = local_preview.get();
   scoped_ptr<VideoEncoder> encoder;
@@ -111,6 +154,9 @@
   VideoReceiveStream::Config receive_config;
   receive_config.rtp.remote_ssrc = send_config.rtp.ssrcs[0];
   receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
+  receive_config.rtp.nack.rtp_history_ms = 1000;
+  receive_config.rtp.rtx[kRtxPayloadType].ssrc = kSendRtxSsrc;
+  receive_config.rtp.rtx[kRtxPayloadType].payload_type = kRtxPayloadType;
   receive_config.renderer = loopback_video.get();
   VideoCodec codec =
       test::CreateDecoderVideoCodec(send_config.encoder_settings);