Integrate fake_network_pipe into direct_transport.
TEST=trybots
R=mflodman@webrtc.org, pbos@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/5529004
git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5321 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/test/direct_transport.cc b/test/direct_transport.cc
index 7b3ff22..96852ed 100644
--- a/test/direct_transport.cc
+++ b/test/direct_transport.cc
@@ -23,20 +23,19 @@
thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
clock_(Clock::GetRealTimeClock()),
shutting_down_(false),
- receiver_(NULL),
- delay_ms_(0) {
+ fake_network_(FakeNetworkPipe::Config()) {
unsigned int thread_id;
EXPECT_TRUE(thread_->Start(thread_id));
}
-DirectTransport::DirectTransport(int delay_ms)
+DirectTransport::DirectTransport(
+ const FakeNetworkPipe::Config& config)
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
packet_event_(EventWrapper::Create()),
thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
clock_(Clock::GetRealTimeClock()),
shutting_down_(false),
- receiver_(NULL),
- delay_ms_(delay_ms) {
+ fake_network_(config) {
unsigned int thread_id;
EXPECT_TRUE(thread_->Start(thread_id));
}
@@ -54,37 +53,19 @@
}
void DirectTransport::SetReceiver(PacketReceiver* receiver) {
- receiver_ = receiver;
+ fake_network_.SetReceiver(receiver);
}
bool DirectTransport::SendRtp(const uint8_t* data, size_t length) {
- QueuePacket(data, length, clock_->TimeInMilliseconds() + delay_ms_);
+ fake_network_.SendPacket(data, length);
+ packet_event_->Set();
return true;
}
bool DirectTransport::SendRtcp(const uint8_t* data, size_t length) {
- QueuePacket(data, length, clock_->TimeInMilliseconds() + delay_ms_);
- return true;
-}
-
-DirectTransport::Packet::Packet() : length(0), delivery_time_ms(0) {}
-
-DirectTransport::Packet::Packet(const uint8_t* data,
- size_t length,
- int64_t delivery_time_ms)
- : length(length), delivery_time_ms(delivery_time_ms) {
- EXPECT_LE(length, sizeof(this->data));
- memcpy(this->data, data, length);
-}
-
-void DirectTransport::QueuePacket(const uint8_t* data,
- size_t length,
- int64_t delivery_time_ms) {
- CriticalSectionScoped crit(lock_.get());
- if (receiver_ == NULL)
- return;
- packet_queue_.push_back(Packet(data, length, delivery_time_ms));
+ fake_network_.SendPacket(data, length);
packet_event_->Set();
+ return true;
}
bool DirectTransport::NetworkProcess(void* transport) {
@@ -92,44 +73,20 @@
}
bool DirectTransport::SendPackets() {
- while (true) {
- Packet p;
- {
- CriticalSectionScoped crit(lock_.get());
- if (packet_queue_.empty())
+ fake_network_.Process();
+ int wait_time_ms = fake_network_.TimeUntilNextProcess();
+ if (wait_time_ms > 0) {
+ switch (packet_event_->Wait(wait_time_ms)) {
+ case kEventSignaled:
+ packet_event_->Reset();
break;
- p = packet_queue_.front();
- if (p.delivery_time_ms > clock_->TimeInMilliseconds())
+ case kEventTimeout:
break;
- packet_queue_.pop_front();
- }
- receiver_->DeliverPacket(p.data, p.length);
- }
- uint32_t time_until_next_delivery = WEBRTC_EVENT_INFINITE;
- {
- CriticalSectionScoped crit(lock_.get());
- if (!packet_queue_.empty()) {
- int64_t now_ms = clock_->TimeInMilliseconds();
- const int64_t delivery_time_ms = packet_queue_.front().delivery_time_ms;
- if (delivery_time_ms > now_ms) {
- time_until_next_delivery = delivery_time_ms - now_ms;
- } else {
- time_until_next_delivery = 0;
- }
+ case kEventError:
+ // TODO(pbos): Log a warning here?
+ return true;
}
}
-
- switch (packet_event_->Wait(time_until_next_delivery)) {
- case kEventSignaled:
- packet_event_->Reset();
- break;
- case kEventTimeout:
- break;
- case kEventError:
- // TODO(pbos): Log a warning here?
- return true;
- }
-
CriticalSectionScoped crit(lock_.get());
return shutting_down_ ? false : true;
}
diff --git a/test/direct_transport.h b/test/direct_transport.h
index b6021cb..660ffec 100644
--- a/test/direct_transport.h
+++ b/test/direct_transport.h
@@ -18,6 +18,7 @@
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
+#include "webrtc/test/fake_network_pipe.h"
#include "webrtc/transport.h"
namespace webrtc {
@@ -30,7 +31,7 @@
class DirectTransport : public newapi::Transport {
public:
DirectTransport();
- explicit DirectTransport(int delay_ms);
+ explicit DirectTransport(const FakeNetworkPipe::Config& config);
~DirectTransport();
virtual void StopSending();
@@ -40,19 +41,6 @@
virtual bool SendRtcp(const uint8_t* data, size_t length) OVERRIDE;
private:
- struct Packet {
- Packet();
- Packet(const uint8_t* data, size_t length, int64_t delivery_time_ms);
-
- uint8_t data[1500];
- size_t length;
- int64_t delivery_time_ms;
- };
-
- void QueuePacket(const uint8_t* data,
- size_t length,
- int64_t delivery_time_ms);
-
static bool NetworkProcess(void* transport);
bool SendPackets();
@@ -63,10 +51,7 @@
bool shutting_down_;
- std::deque<Packet> packet_queue_;
- PacketReceiver* receiver_;
- // TODO(stefan): Replace this with FakeNetworkPipe.
- const int delay_ms_;
+ FakeNetworkPipe fake_network_;
};
} // namespace test
} // namespace webrtc
diff --git a/test/fake_network_pipe.cc b/test/fake_network_pipe.cc
new file mode 100644
index 0000000..5a2424e
--- /dev/null
+++ b/test/fake_network_pipe.cc
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+#include "webrtc/test/fake_network_pipe.h"
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+#include <algorithm>
+
+#include "webrtc/call.h"
+#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+
+namespace webrtc {
+
+const double kPi = 3.14159265;
+const int kDefaultProcessIntervalMs = 30;
+
+static int GaussianRandom(int mean_delay_ms, int standard_deviation_ms) {
+ // Creating a Normal distribution variable from two independent uniform
+ // variables based on the Box-Muller transform.
+ double uniform1 = (rand() + 1.0) / (RAND_MAX + 1.0); // NOLINT
+ double uniform2 = (rand() + 1.0) / (RAND_MAX + 1.0); // NOLINT
+ return static_cast<int>(mean_delay_ms + standard_deviation_ms *
+ sqrt(-2 * log(uniform1)) * cos(2 * kPi * uniform2));
+}
+
+class NetworkPacket {
+ public:
+ NetworkPacket(const uint8_t* data, size_t length, int64_t send_time,
+ int64_t arrival_time)
+ : data_(NULL),
+ data_length_(length),
+ send_time_(send_time),
+ arrival_time_(arrival_time) {
+ data_ = new uint8_t[length];
+ memcpy(data_, data, length);
+ }
+ ~NetworkPacket() {
+ delete [] data_;
+ }
+
+ uint8_t* data() const { return data_; }
+ size_t data_length() const { return data_length_; }
+ 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;
+ }
+
+ private:
+ // The packet data.
+ uint8_t* data_;
+ // Length of data_.
+ size_t data_length_;
+ // The time the packet was sent out on the network.
+ const int64_t send_time_;
+ // The time the packet should arrive at the reciver.
+ int64_t arrival_time_;
+};
+
+FakeNetworkPipe::FakeNetworkPipe(
+ const FakeNetworkPipe::Config& config)
+ : lock_(CriticalSectionWrapper::CreateCriticalSection()),
+ packet_receiver_(NULL),
+ config_(config),
+ dropped_packets_(0),
+ sent_packets_(0),
+ total_packet_delay_(0),
+ next_process_time_(TickTime::MillisecondTimestamp()) {
+}
+
+FakeNetworkPipe::~FakeNetworkPipe() {
+ while (!capacity_link_.empty()) {
+ delete capacity_link_.front();
+ capacity_link_.pop();
+ }
+ while (!delay_link_.empty()) {
+ delete delay_link_.front();
+ delay_link_.pop();
+ }
+}
+
+void FakeNetworkPipe::SetReceiver(PacketReceiver* receiver) {
+ packet_receiver_ = receiver;
+}
+
+void FakeNetworkPipe::SendPacket(const uint8_t* data, size_t data_length) {
+ // A NULL packet_receiver_ means that this pipe will terminate the flow of
+ // packets.
+ if (packet_receiver_ == NULL)
+ return;
+ CriticalSectionScoped crit(lock_.get());
+ if (config_.queue_length > 0 &&
+ capacity_link_.size() >= config_.queue_length) {
+ // Too many packet on the link, drop this one.
+ ++dropped_packets_;
+ return;
+ }
+
+ int64_t time_now = TickTime::MillisecondTimestamp();
+
+ // Delay introduced by the link capacity.
+ int64_t capacity_delay_ms = 0;
+ if (config_.link_capacity_kbps > 0)
+ capacity_delay_ms = data_length / (config_.link_capacity_kbps / 8);
+ int64_t network_start_time = time_now;
+
+ // Check if there already are packets on the link and change network start
+ // time if there is.
+ if (capacity_link_.size() > 0)
+ network_start_time = capacity_link_.back()->arrival_time();
+
+ int64_t arrival_time = network_start_time + capacity_delay_ms;
+ NetworkPacket* packet = new NetworkPacket(data, data_length, time_now,
+ arrival_time);
+ capacity_link_.push(packet);
+}
+
+float FakeNetworkPipe::PercentageLoss() {
+ CriticalSectionScoped crit(lock_.get());
+ if (sent_packets_ == 0)
+ return 0;
+
+ return static_cast<float>(dropped_packets_) /
+ (sent_packets_ + dropped_packets_);
+}
+
+int FakeNetworkPipe::AverageDelay() {
+ CriticalSectionScoped crit(lock_.get());
+ if (sent_packets_ == 0)
+ return 0;
+
+ return total_packet_delay_ / static_cast<int>(sent_packets_);
+}
+
+void FakeNetworkPipe::Process() {
+ int64_t time_now = TickTime::MillisecondTimestamp();
+ std::queue<NetworkPacket*> packets_to_deliver;
+ {
+ CriticalSectionScoped crit(lock_.get());
+ // Check the capacity link first.
+ while (capacity_link_.size() > 0 &&
+ time_now >= capacity_link_.front()->arrival_time()) {
+ // Time to get this packet.
+ NetworkPacket* packet = capacity_link_.front();
+ capacity_link_.pop();
+
+ // 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,
+ config_.delay_standard_deviation_ms);
+ if (delay_link_.size() > 0 &&
+ packet->arrival_time() + extra_delay <
+ delay_link_.back()->arrival_time()) {
+ extra_delay = delay_link_.back()->arrival_time() -
+ packet->arrival_time();
+ }
+ packet->IncrementArrivalTime(extra_delay);
+ if (packet->arrival_time() < next_process_time_)
+ next_process_time_ = packet->arrival_time();
+ delay_link_.push(packet);
+ }
+
+ // Check the extra delay queue.
+ while (delay_link_.size() > 0 &&
+ time_now >= delay_link_.front()->arrival_time()) {
+ // Deliver this packet.
+ NetworkPacket* packet = delay_link_.front();
+ packets_to_deliver.push(packet);
+ delay_link_.pop();
+ // |time_now| might be later than when the packet should have arrived, due
+ // to NetworkProcess being called too late. For stats, use the time it
+ // should have been on the link.
+ total_packet_delay_ += packet->arrival_time() - packet->send_time();
+ }
+ sent_packets_ += packets_to_deliver.size();
+ }
+ while (!packets_to_deliver.empty()) {
+ NetworkPacket* packet = packets_to_deliver.front();
+ packets_to_deliver.pop();
+ packet_receiver_->DeliverPacket(packet->data(), packet->data_length());
+ delete packet;
+ }
+}
+
+int FakeNetworkPipe::TimeUntilNextProcess() const {
+ CriticalSectionScoped crit(lock_.get());
+ if (capacity_link_.size() == 0 || delay_link_.size() == 0)
+ return kDefaultProcessIntervalMs;
+ return std::max(static_cast<int>(next_process_time_ -
+ TickTime::MillisecondTimestamp()), 0);
+}
+
+} // namespace webrtc
diff --git a/video_engine/test/libvietest/include/fake_network_pipe.h b/test/fake_network_pipe.h
similarity index 60%
rename from video_engine/test/libvietest/include/fake_network_pipe.h
rename to test/fake_network_pipe.h
index ece1472..e750457 100644
--- a/video_engine/test/libvietest/include/fake_network_pipe.h
+++ b/test/fake_network_pipe.h
@@ -8,12 +8,13 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-#ifndef WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_FAKE_NETWORK_PIPE_H_
-#define WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_FAKE_NETWORK_PIPE_H_
+#ifndef WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
+#define WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
#include <queue>
#include "webrtc/system_wrappers/interface/constructor_magic.h"
+#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
@@ -21,14 +22,7 @@
class CriticalSectionWrapper;
class NetworkPacket;
-
-class PacketReceiver {
- public:
- // Delivers a new packet to the receive side of the network pipe. The
- // implementor of PacketReceiver now owns the memory.
- virtual void IncomingPacket(uint8_t* packet, int length) = 0;
- virtual ~PacketReceiver() {}
-};
+class PacketReceiver;
// Class faking a network link. This is a simple and naive solution just faking
// capacity and adding an extra transport delay in addition to the capacity
@@ -37,18 +31,15 @@
// TODO(mflodman) Add random and bursty packet loss.
class FakeNetworkPipe {
public:
- struct Configuration {
- Configuration()
- : packet_receiver(NULL),
- queue_length(0),
+ struct Config {
+ Config()
+ : queue_length(0),
queue_delay_ms(0),
delay_standard_deviation_ms(0),
link_capacity_kbps(0),
loss_percent(0) {
}
- // Callback to deliver received packets.
- PacketReceiver* packet_receiver;
- // Queue lenght in number of packets.
+ // Queue length in number of packets.
size_t queue_length;
// Delay in addition to capacity induced delay.
int queue_delay_ms;
@@ -60,44 +51,45 @@
int loss_percent;
};
- explicit FakeNetworkPipe(const FakeNetworkPipe::Configuration& configuration);
+ explicit FakeNetworkPipe(const FakeNetworkPipe::Config& config);
~FakeNetworkPipe();
+ // Must not be called in parallel with SendPacket or Process.
+ void SetReceiver(PacketReceiver* receiver);
+
// Sends a new packet to the link.
- void SendPacket(void* packet, int packet_length);
+ void SendPacket(const uint8_t* packet, size_t packet_length);
// Processes the network queues and trigger PacketReceiver::IncomingPacket for
// packets ready to be delivered.
- void NetworkProcess();
+ void Process();
+ int TimeUntilNextProcess() const;
// Get statistics.
float PercentageLoss();
int AverageDelay();
- int dropped_packets() { return dropped_packets_; }
- int sent_packets() { return sent_packets_; }
+ size_t dropped_packets() { return dropped_packets_; }
+ size_t sent_packets() { return sent_packets_; }
private:
+ scoped_ptr<CriticalSectionWrapper> lock_;
PacketReceiver* packet_receiver_;
- scoped_ptr<CriticalSectionWrapper> link_cs_;
std::queue<NetworkPacket*> capacity_link_;
std::queue<NetworkPacket*> delay_link_;
// Link configuration.
- const size_t queue_length_;
- const int queue_delay_ms_;
- const int queue_delay_deviation_ms_;
- const int link_capacity_bytes_ms_; // In bytes per ms.
-
- const int loss_percent_;
+ Config config_;
// Statistics.
- int dropped_packets_;
- int sent_packets_;
+ size_t dropped_packets_;
+ size_t sent_packets_;
int total_packet_delay_;
+ int64_t next_process_time_;
+
DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe);
};
} // namespace webrtc
-#endif // WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_FAKE_NETWORK_PIPE_H_
+#endif // WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
diff --git a/video_engine/test/libvietest/testbed/fake_network_pipe_unittest.cc b/test/fake_network_pipe_unittest.cc
similarity index 79%
rename from video_engine/test/libvietest/testbed/fake_network_pipe_unittest.cc
rename to test/fake_network_pipe_unittest.cc
index 7747302..1245f61 100644
--- a/video_engine/test/libvietest/testbed/fake_network_pipe_unittest.cc
+++ b/test/fake_network_pipe_unittest.cc
@@ -11,9 +11,10 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/call.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
-#include "webrtc/video_engine/test/libvietest/include/fake_network_pipe.h"
+#include "webrtc/test/fake_network_pipe.h"
using ::testing::_;
using ::testing::AnyNumber;
@@ -27,12 +28,12 @@
MockReceiver() {}
virtual ~MockReceiver() {}
- void IncomingPacket(uint8_t* data, int length) {
- IncomingData(data, length);
+ void IncomingPacket(const uint8_t* data, size_t length) {
+ DeliverPacket(data, length);
delete [] data;
}
- MOCK_METHOD2(IncomingData, void(uint8_t*, int));
+ MOCK_METHOD2(DeliverPacket, bool(const uint8_t*, size_t));
};
class FakeNetworkPipeTest : public ::testing::Test {
@@ -63,11 +64,11 @@
// Test the capacity link and verify we get as many packets as we expect.
TEST_F(FakeNetworkPipeTest, CapacityTest) {
- FakeNetworkPipe::Configuration config;
- config.packet_receiver = receiver_.get();
+ FakeNetworkPipe::Config config;
config.queue_length = 20;
config.link_capacity_kbps = 80;
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
+ pipe->SetReceiver(receiver_.get());
// Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to
// get through the pipe.
@@ -80,37 +81,37 @@
kPacketSize);
// Time haven't increased yet, so we souldn't get any packets.
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(0);
- pipe->NetworkProcess();
+ pipe->Process();
// Advance enough time to release one packet.
TickTime::AdvanceFakeClock(kPacketTimeMs);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(1);
- pipe->NetworkProcess();
+ pipe->Process();
// Release all but one packet
TickTime::AdvanceFakeClock(9 * kPacketTimeMs - 1);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(8);
- pipe->NetworkProcess();
+ pipe->Process();
// And the last one.
TickTime::AdvanceFakeClock(1);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(1);
- pipe->NetworkProcess();
+ pipe->Process();
}
// Test the extra network delay.
TEST_F(FakeNetworkPipeTest, ExtraDelayTest) {
- FakeNetworkPipe::Configuration config;
- config.packet_receiver = receiver_.get();
+ FakeNetworkPipe::Config config;
config.queue_length = 20;
config.queue_delay_ms = 100;
config.link_capacity_kbps = 80;
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
+ pipe->SetReceiver(receiver_.get());
const int kNumPackets = 2;
const int kPacketSize = 1000;
@@ -122,31 +123,31 @@
// Increase more than kPacketTimeMs, but not more than the extra delay.
TickTime::AdvanceFakeClock(kPacketTimeMs);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(0);
- pipe->NetworkProcess();
+ pipe->Process();
// Advance the network delay to get the first packet.
TickTime::AdvanceFakeClock(config.queue_delay_ms);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(1);
- pipe->NetworkProcess();
+ pipe->Process();
// Advance one more kPacketTimeMs to get the last packet.
TickTime::AdvanceFakeClock(kPacketTimeMs);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(1);
- pipe->NetworkProcess();
+ pipe->Process();
}
// Test the number of buffers and packets are dropped when sending too many
// packets too quickly.
TEST_F(FakeNetworkPipeTest, QueueLengthTest) {
- FakeNetworkPipe::Configuration config;
- config.packet_receiver = receiver_.get();
+ FakeNetworkPipe::Config config;
config.queue_length = 2;
config.link_capacity_kbps = 80;
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
+ pipe->SetReceiver(receiver_.get());
const int kPacketSize = 1000;
const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps,
@@ -158,19 +159,19 @@
// Increase time enough to deliver all three packets, verify only two are
// delivered.
TickTime::AdvanceFakeClock(3 * kPacketTimeMs);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(2);
- pipe->NetworkProcess();
+ pipe->Process();
}
// Test we get statistics as expected.
TEST_F(FakeNetworkPipeTest, StatisticsTest) {
- FakeNetworkPipe::Configuration config;
- config.packet_receiver = receiver_.get();
+ FakeNetworkPipe::Config config;
config.queue_length = 2;
config.queue_delay_ms = 20;
config.link_capacity_kbps = 80;
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
+ pipe->SetReceiver(receiver_.get());
const int kPacketSize = 1000;
const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps,
@@ -180,15 +181,15 @@
SendPackets(pipe.get(), 3, kPacketSize);
TickTime::AdvanceFakeClock(3 * kPacketTimeMs + config.queue_delay_ms);
- EXPECT_CALL(*receiver_, IncomingData(_, _))
+ EXPECT_CALL(*receiver_, DeliverPacket(_, _))
.Times(2);
- pipe->NetworkProcess();
+ pipe->Process();
// Packet 1: kPacketTimeMs + config.queue_delay_ms,
// packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average.
EXPECT_EQ(pipe->AverageDelay(), 170);
- EXPECT_EQ(pipe->sent_packets(), 2);
- EXPECT_EQ(pipe->dropped_packets(), 1);
+ EXPECT_EQ(pipe->sent_packets(), 2u);
+ EXPECT_EQ(pipe->dropped_packets(), 1u);
EXPECT_EQ(pipe->PercentageLoss(), 1/3.f);
}
diff --git a/test/rtp_rtcp_observer.h b/test/rtp_rtcp_observer.h
index 56c96fa..3b4ad7b 100644
--- a/test/rtp_rtcp_observer.h
+++ b/test/rtp_rtcp_observer.h
@@ -49,7 +49,8 @@
}
protected:
- RtpRtcpObserver(unsigned int event_timeout_ms, int delay_ms)
+ RtpRtcpObserver(unsigned int event_timeout_ms,
+ const FakeNetworkPipe::Config& configuration)
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
observation_complete_(EventWrapper::Create()),
parser_(RtpHeaderParser::Create()),
@@ -57,12 +58,12 @@
this,
&RtpRtcpObserver::OnSendRtp,
&RtpRtcpObserver::OnSendRtcp,
- delay_ms),
+ configuration),
receive_transport_(lock_.get(),
this,
&RtpRtcpObserver::OnReceiveRtp,
&RtpRtcpObserver::OnReceiveRtcp,
- delay_ms),
+ configuration),
timeout_ms_(event_timeout_ms) {}
explicit RtpRtcpObserver(unsigned int event_timeout_ms)
@@ -73,12 +74,12 @@
this,
&RtpRtcpObserver::OnSendRtp,
&RtpRtcpObserver::OnSendRtcp,
- 0),
+ FakeNetworkPipe::Config()),
receive_transport_(lock_.get(),
this,
&RtpRtcpObserver::OnReceiveRtp,
&RtpRtcpObserver::OnReceiveRtcp,
- 0),
+ FakeNetworkPipe::Config()),
timeout_ms_(event_timeout_ms) {}
enum Action {
@@ -113,8 +114,8 @@
RtpRtcpObserver* observer,
PacketTransportAction on_rtp,
PacketTransportAction on_rtcp,
- int delay_ms)
- : test::DirectTransport(delay_ms),
+ const FakeNetworkPipe::Config& configuration)
+ : test::DirectTransport(configuration),
lock_(lock),
observer_(observer),
on_rtp_(on_rtp),
diff --git a/test/webrtc_test_common.gyp b/test/webrtc_test_common.gyp
index eae66a0..eac8b97 100644
--- a/test/webrtc_test_common.gyp
+++ b/test/webrtc_test_common.gyp
@@ -24,6 +24,8 @@
'fake_decoder.h',
'fake_encoder.cc',
'fake_encoder.h',
+ 'fake_network_pipe.cc',
+ 'fake_network_pipe.h',
'flags.cc',
'flags.h',
'frame_generator_capturer.cc',
@@ -124,4 +126,23 @@
],
},
],
+ 'conditions': [
+ ['include_tests==1', {
+ 'targets': [
+ {
+ 'target_name': 'webrtc_test_common_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ 'webrtc_test_common',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(webrtc_root)/test/test.gyp:test_support_main',
+ ],
+ 'sources': [
+ 'fake_network_pipe_unittest.cc',
+ ],
+ },
+ ], #targets
+ }], # include_tests
+ ], # conditions
}
diff --git a/video/call_perf_tests.cc b/video/call_perf_tests.cc
index 49c6488..0637ec3 100644
--- a/video/call_perf_tests.cc
+++ b/video/call_perf_tests.cc
@@ -49,8 +49,8 @@
class SyncRtcpObserver : public test::RtpRtcpObserver {
public:
- explicit SyncRtcpObserver(int delay_ms)
- : test::RtpRtcpObserver(kLongTimeoutMs, delay_ms),
+ explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config)
+ : test::RtpRtcpObserver(kLongTimeoutMs, config),
critical_section_(CriticalSectionWrapper::CreateCriticalSection()) {}
virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
@@ -119,7 +119,7 @@
int voe_channel,
VoEVideoSync* voe_sync,
SyncRtcpObserver* audio_observer)
- : SyncRtcpObserver(0),
+ : SyncRtcpObserver(FakeNetworkPipe::Config()),
clock_(clock),
voe_channel_(voe_channel),
voe_sync_(voe_sync),
@@ -189,8 +189,9 @@
EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
int channel = voe_base->CreateChannel();
- const int kVoiceDelayMs = 500;
- SyncRtcpObserver audio_observer(kVoiceDelayMs);
+ FakeNetworkPipe::Config net_config;
+ net_config.queue_delay_ms = 500;
+ SyncRtcpObserver audio_observer(net_config);
VideoRtcpAndSyncObserver observer(
Clock::GetRealTimeClock(), channel, voe_sync, &audio_observer);
diff --git a/video_engine/test/libvietest/libvietest.gypi b/video_engine/test/libvietest/libvietest.gypi
index a3ba22e..33d0b0f 100644
--- a/video_engine/test/libvietest/libvietest.gypi
+++ b/video_engine/test/libvietest/libvietest.gypi
@@ -28,14 +28,12 @@
'helpers/vie_to_file_renderer.cc',
# Testbed classes
- 'include/fake_network_pipe.h',
'include/tb_capture_device.h',
'include/tb_external_transport.h',
'include/tb_I420_codec.h',
'include/tb_interfaces.h',
'include/tb_video_channel.h',
- 'testbed/fake_network_pipe.cc',
'testbed/tb_capture_device.cc',
'testbed/tb_external_transport.cc',
'testbed/tb_I420_codec.cc',
@@ -48,23 +46,4 @@
],
},
],
- 'conditions': [
- ['include_tests==1', {
- 'targets': [
- {
- 'target_name': 'libvietest_unittests',
- 'type': 'executable',
- 'dependencies': [
- 'libvietest',
- '<(DEPTH)/testing/gtest.gyp:gtest',
- '<(DEPTH)/testing/gmock.gyp:gmock',
- '<(webrtc_root)/test/test.gyp:test_support_main',
- ],
- 'sources': [
- 'testbed/fake_network_pipe_unittest.cc',
- ],
- },
- ], #targets
- }], # include_tests
- ], # conditions
}
diff --git a/video_engine/test/libvietest/testbed/fake_network_pipe.cc b/video_engine/test/libvietest/testbed/fake_network_pipe.cc
deleted file mode 100644
index b1c8eb2..0000000
--- a/video_engine/test/libvietest/testbed/fake_network_pipe.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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.
- */
-
-#include "webrtc/video_engine/test/libvietest/include/fake_network_pipe.h"
-
-#include <assert.h>
-#include <math.h>
-#include <string.h>
-
-#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
-#include "webrtc/system_wrappers/interface/tick_util.h"
-
-namespace webrtc {
-
-const double kPi = 3.14159265;
-
-static int GaussianRandom(int mean_delay_ms, int standard_deviation_ms) {
- // Creating a Normal distribution variable from two independent uniform
- // variables based on the Box-Muller transform.
- double uniform1 = (rand() + 1.0) / (RAND_MAX + 1.0); // NOLINT
- double uniform2 = (rand() + 1.0) / (RAND_MAX + 1.0); // NOLINT
- return static_cast<int>(mean_delay_ms + standard_deviation_ms *
- sqrt(-2 * log(uniform1)) * cos(2 * kPi * uniform2));
-}
-
-class NetworkPacket {
- public:
- NetworkPacket(void* data, int length, int64_t send_time, int64_t arrival_time)
- : data_(NULL),
- data_length_(length),
- send_time_(send_time),
- arrival_time_(arrival_time) {
- data_ = new uint8_t[length];
- memcpy(data_, data, length);
- }
- ~NetworkPacket() {}
-
- void ReleaseData() {
- delete [] data_;
- data_ = NULL;
- }
- uint8_t* data() const { return data_; }
- int data_length() const { return data_length_; }
- 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;
- }
-
- private:
- // The packet data.
- uint8_t* data_;
- // Length of data_.
- int data_length_;
- // The time the packet was sent out on the network.
- const int64_t send_time_;
- // The time the packet should arrive at the reciver.
- int64_t arrival_time_;
-};
-
-FakeNetworkPipe::FakeNetworkPipe(
- const FakeNetworkPipe::Configuration& configuration)
- : packet_receiver_(configuration.packet_receiver),
- link_cs_(CriticalSectionWrapper::CreateCriticalSection()),
- queue_length_(configuration.queue_length),
- queue_delay_ms_(configuration.queue_delay_ms),
- queue_delay_deviation_ms_(configuration.delay_standard_deviation_ms),
- link_capacity_bytes_ms_(configuration.link_capacity_kbps / 8),
- loss_percent_(configuration.loss_percent),
- dropped_packets_(0),
- sent_packets_(0),
- total_packet_delay_(0) {
- assert(link_capacity_bytes_ms_ > 0);
- assert(packet_receiver_ != NULL);
-}
-
-FakeNetworkPipe::~FakeNetworkPipe() {
-}
-
-void FakeNetworkPipe::SendPacket(void* data, int data_length) {
- CriticalSectionScoped cs(link_cs_.get());
- if (capacity_link_.size() >= queue_length_) {
- // Too many packet on the link, drop this one.
- ++dropped_packets_;
- return;
- }
-
- int64_t time_now = TickTime::MillisecondTimestamp();
-
- // Delay introduced by the link capacity.
- int64_t capacity_delay_ms = data_length / link_capacity_bytes_ms_;
- int64_t network_start_time = time_now;
-
- // Check if there already are packets on the link and change network start
- // time if there is.
- if (capacity_link_.size() > 0)
- network_start_time = capacity_link_.back()->arrival_time();
-
- int64_t arrival_time = network_start_time + capacity_delay_ms;
- NetworkPacket* packet = new NetworkPacket(data, data_length, time_now,
- arrival_time);
- capacity_link_.push(packet);
-}
-
-float FakeNetworkPipe::PercentageLoss() {
- CriticalSectionScoped cs(link_cs_.get());
- if (sent_packets_ == 0)
- return 0;
-
- return static_cast<float>(dropped_packets_) /
- (sent_packets_ + dropped_packets_);
-}
-
-int FakeNetworkPipe::AverageDelay() {
- CriticalSectionScoped cs(link_cs_.get());
- if (sent_packets_ == 0)
- return 0;
-
- return total_packet_delay_ / sent_packets_;
-}
-
-void FakeNetworkPipe::NetworkProcess() {
- CriticalSectionScoped cs(link_cs_.get());
- if (capacity_link_.size() == 0 && delay_link_.size() == 0)
- return;
-
- int64_t time_now = TickTime::MillisecondTimestamp();
-
- // Check the capacity link first.
- while (capacity_link_.size() > 0 &&
- time_now >= capacity_link_.front()->arrival_time()) {
- // Time to get this packet.
- NetworkPacket* packet = capacity_link_.front();
- capacity_link_.pop();
-
- // 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(queue_delay_ms_,
- queue_delay_deviation_ms_);
- if (delay_link_.size() > 0 &&
- packet->arrival_time() + extra_delay <
- delay_link_.back()->arrival_time()) {
- extra_delay = delay_link_.back()->arrival_time() - packet->arrival_time();
- }
- packet->IncrementArrivalTime(extra_delay);
- delay_link_.push(packet);
- }
-
- // Check the extra delay queue.
- while (delay_link_.size() > 0 &&
- time_now >= delay_link_.front()->arrival_time()) {
- // Deliver this packet.
- NetworkPacket* packet = delay_link_.front();
- delay_link_.pop();
- packet_receiver_->IncomingPacket(packet->data(), packet->data_length());
- ++sent_packets_;
-
- // |time_now| might be later than when the packet should have arrived, due
- // to NetworkProcess being called too late. For stats, use the time it
- // should have been on the link.
- total_packet_delay_ += packet->arrival_time() - packet->send_time();
- delete packet;
- }
-}
-
-} // namespace webrtc
diff --git a/webrtc.gyp b/webrtc.gyp
index ed101b6..e78dba6 100644
--- a/webrtc.gyp
+++ b/webrtc.gyp
@@ -43,6 +43,7 @@
'system_wrappers/source/system_wrappers_tests.gyp:*',
'test/metrics.gyp:*',
'test/test.gyp:*',
+ 'test/webrtc_test_common.gyp:webrtc_test_common_unittests',
'tools/tools.gyp:*',
'webrtc_tests',
],