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@5321 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -23,20 +23,19 @@ DirectTransport::DirectTransport()
|
|||||||
thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
|
thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
|
||||||
clock_(Clock::GetRealTimeClock()),
|
clock_(Clock::GetRealTimeClock()),
|
||||||
shutting_down_(false),
|
shutting_down_(false),
|
||||||
receiver_(NULL),
|
fake_network_(FakeNetworkPipe::Config()) {
|
||||||
delay_ms_(0) {
|
|
||||||
unsigned int thread_id;
|
unsigned int thread_id;
|
||||||
EXPECT_TRUE(thread_->Start(thread_id));
|
EXPECT_TRUE(thread_->Start(thread_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectTransport::DirectTransport(int delay_ms)
|
DirectTransport::DirectTransport(
|
||||||
|
const FakeNetworkPipe::Config& config)
|
||||||
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
|
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
packet_event_(EventWrapper::Create()),
|
packet_event_(EventWrapper::Create()),
|
||||||
thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
|
thread_(ThreadWrapper::CreateThread(NetworkProcess, this)),
|
||||||
clock_(Clock::GetRealTimeClock()),
|
clock_(Clock::GetRealTimeClock()),
|
||||||
shutting_down_(false),
|
shutting_down_(false),
|
||||||
receiver_(NULL),
|
fake_network_(config) {
|
||||||
delay_ms_(delay_ms) {
|
|
||||||
unsigned int thread_id;
|
unsigned int thread_id;
|
||||||
EXPECT_TRUE(thread_->Start(thread_id));
|
EXPECT_TRUE(thread_->Start(thread_id));
|
||||||
}
|
}
|
||||||
@ -54,37 +53,19 @@ void DirectTransport::StopSending() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DirectTransport::SetReceiver(PacketReceiver* receiver) {
|
void DirectTransport::SetReceiver(PacketReceiver* receiver) {
|
||||||
receiver_ = receiver;
|
fake_network_.SetReceiver(receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectTransport::SendRtp(const uint8_t* data, size_t length) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectTransport::SendRtcp(const uint8_t* data, size_t length) {
|
bool DirectTransport::SendRtcp(const uint8_t* data, size_t length) {
|
||||||
QueuePacket(data, length, clock_->TimeInMilliseconds() + delay_ms_);
|
fake_network_.SendPacket(data, length);
|
||||||
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));
|
|
||||||
packet_event_->Set();
|
packet_event_->Set();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DirectTransport::NetworkProcess(void* transport) {
|
bool DirectTransport::NetworkProcess(void* transport) {
|
||||||
@ -92,34 +73,10 @@ bool DirectTransport::NetworkProcess(void* transport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DirectTransport::SendPackets() {
|
bool DirectTransport::SendPackets() {
|
||||||
while (true) {
|
fake_network_.Process();
|
||||||
Packet p;
|
int wait_time_ms = fake_network_.TimeUntilNextProcess();
|
||||||
{
|
if (wait_time_ms > 0) {
|
||||||
CriticalSectionScoped crit(lock_.get());
|
switch (packet_event_->Wait(wait_time_ms)) {
|
||||||
if (packet_queue_.empty())
|
|
||||||
break;
|
|
||||||
p = packet_queue_.front();
|
|
||||||
if (p.delivery_time_ms > clock_->TimeInMilliseconds())
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (packet_event_->Wait(time_until_next_delivery)) {
|
|
||||||
case kEventSignaled:
|
case kEventSignaled:
|
||||||
packet_event_->Reset();
|
packet_event_->Reset();
|
||||||
break;
|
break;
|
||||||
@ -129,7 +86,7 @@ bool DirectTransport::SendPackets() {
|
|||||||
// TODO(pbos): Log a warning here?
|
// TODO(pbos): Log a warning here?
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
CriticalSectionScoped crit(lock_.get());
|
CriticalSectionScoped crit(lock_.get());
|
||||||
return shutting_down_ ? false : true;
|
return shutting_down_ ? false : true;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "webrtc/system_wrappers/interface/event_wrapper.h"
|
#include "webrtc/system_wrappers/interface/event_wrapper.h"
|
||||||
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
|
||||||
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
|
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
|
||||||
|
#include "webrtc/test/fake_network_pipe.h"
|
||||||
#include "webrtc/transport.h"
|
#include "webrtc/transport.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -30,7 +31,7 @@ namespace test {
|
|||||||
class DirectTransport : public newapi::Transport {
|
class DirectTransport : public newapi::Transport {
|
||||||
public:
|
public:
|
||||||
DirectTransport();
|
DirectTransport();
|
||||||
explicit DirectTransport(int delay_ms);
|
explicit DirectTransport(const FakeNetworkPipe::Config& config);
|
||||||
~DirectTransport();
|
~DirectTransport();
|
||||||
|
|
||||||
virtual void StopSending();
|
virtual void StopSending();
|
||||||
@ -40,19 +41,6 @@ class DirectTransport : public newapi::Transport {
|
|||||||
virtual bool SendRtcp(const uint8_t* data, size_t length) OVERRIDE;
|
virtual bool SendRtcp(const uint8_t* data, size_t length) OVERRIDE;
|
||||||
|
|
||||||
private:
|
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);
|
static bool NetworkProcess(void* transport);
|
||||||
bool SendPackets();
|
bool SendPackets();
|
||||||
|
|
||||||
@ -63,10 +51,7 @@ class DirectTransport : public newapi::Transport {
|
|||||||
|
|
||||||
bool shutting_down_;
|
bool shutting_down_;
|
||||||
|
|
||||||
std::deque<Packet> packet_queue_;
|
FakeNetworkPipe fake_network_;
|
||||||
PacketReceiver* receiver_;
|
|
||||||
// TODO(stefan): Replace this with FakeNetworkPipe.
|
|
||||||
const int delay_ms_;
|
|
||||||
};
|
};
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
203
webrtc/test/fake_network_pipe.cc
Normal file
203
webrtc/test/fake_network_pipe.cc
Normal file
@ -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
|
@ -8,12 +8,13 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_FAKE_NETWORK_PIPE_H_
|
#ifndef WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
|
||||||
#define WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_FAKE_NETWORK_PIPE_H_
|
#define WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#include "webrtc/system_wrappers/interface/constructor_magic.h"
|
#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/system_wrappers/interface/scoped_ptr.h"
|
||||||
#include "webrtc/typedefs.h"
|
#include "webrtc/typedefs.h"
|
||||||
|
|
||||||
@ -21,14 +22,7 @@ namespace webrtc {
|
|||||||
|
|
||||||
class CriticalSectionWrapper;
|
class CriticalSectionWrapper;
|
||||||
class NetworkPacket;
|
class NetworkPacket;
|
||||||
|
class PacketReceiver;
|
||||||
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 faking a network link. This is a simple and naive solution just faking
|
// 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
|
// capacity and adding an extra transport delay in addition to the capacity
|
||||||
@ -37,18 +31,15 @@ class PacketReceiver {
|
|||||||
// TODO(mflodman) Add random and bursty packet loss.
|
// TODO(mflodman) Add random and bursty packet loss.
|
||||||
class FakeNetworkPipe {
|
class FakeNetworkPipe {
|
||||||
public:
|
public:
|
||||||
struct Configuration {
|
struct Config {
|
||||||
Configuration()
|
Config()
|
||||||
: packet_receiver(NULL),
|
: queue_length(0),
|
||||||
queue_length(0),
|
|
||||||
queue_delay_ms(0),
|
queue_delay_ms(0),
|
||||||
delay_standard_deviation_ms(0),
|
delay_standard_deviation_ms(0),
|
||||||
link_capacity_kbps(0),
|
link_capacity_kbps(0),
|
||||||
loss_percent(0) {
|
loss_percent(0) {
|
||||||
}
|
}
|
||||||
// Callback to deliver received packets.
|
// Queue length in number of packets.
|
||||||
PacketReceiver* packet_receiver;
|
|
||||||
// Queue lenght in number of packets.
|
|
||||||
size_t queue_length;
|
size_t queue_length;
|
||||||
// Delay in addition to capacity induced delay.
|
// Delay in addition to capacity induced delay.
|
||||||
int queue_delay_ms;
|
int queue_delay_ms;
|
||||||
@ -60,44 +51,45 @@ class FakeNetworkPipe {
|
|||||||
int loss_percent;
|
int loss_percent;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit FakeNetworkPipe(const FakeNetworkPipe::Configuration& configuration);
|
explicit FakeNetworkPipe(const FakeNetworkPipe::Config& config);
|
||||||
~FakeNetworkPipe();
|
~FakeNetworkPipe();
|
||||||
|
|
||||||
|
// Must not be called in parallel with SendPacket or Process.
|
||||||
|
void SetReceiver(PacketReceiver* receiver);
|
||||||
|
|
||||||
// Sends a new packet to the link.
|
// 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
|
// Processes the network queues and trigger PacketReceiver::IncomingPacket for
|
||||||
// packets ready to be delivered.
|
// packets ready to be delivered.
|
||||||
void NetworkProcess();
|
void Process();
|
||||||
|
int TimeUntilNextProcess() const;
|
||||||
|
|
||||||
// Get statistics.
|
// Get statistics.
|
||||||
float PercentageLoss();
|
float PercentageLoss();
|
||||||
int AverageDelay();
|
int AverageDelay();
|
||||||
int dropped_packets() { return dropped_packets_; }
|
size_t dropped_packets() { return dropped_packets_; }
|
||||||
int sent_packets() { return sent_packets_; }
|
size_t sent_packets() { return sent_packets_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
scoped_ptr<CriticalSectionWrapper> lock_;
|
||||||
PacketReceiver* packet_receiver_;
|
PacketReceiver* packet_receiver_;
|
||||||
scoped_ptr<CriticalSectionWrapper> link_cs_;
|
|
||||||
std::queue<NetworkPacket*> capacity_link_;
|
std::queue<NetworkPacket*> capacity_link_;
|
||||||
std::queue<NetworkPacket*> delay_link_;
|
std::queue<NetworkPacket*> delay_link_;
|
||||||
|
|
||||||
// Link configuration.
|
// Link configuration.
|
||||||
const size_t queue_length_;
|
Config config_;
|
||||||
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_;
|
|
||||||
|
|
||||||
// Statistics.
|
// Statistics.
|
||||||
int dropped_packets_;
|
size_t dropped_packets_;
|
||||||
int sent_packets_;
|
size_t sent_packets_;
|
||||||
int total_packet_delay_;
|
int total_packet_delay_;
|
||||||
|
|
||||||
|
int64_t next_process_time_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe);
|
DISALLOW_COPY_AND_ASSIGN(FakeNetworkPipe);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // WEBRTC_VIDEO_ENGINE_TEST_LIBVIETEST_INCLUDE_FAKE_NETWORK_PIPE_H_
|
#endif // WEBRTC_TEST_FAKE_NETWORK_PIPE_H_
|
@ -11,9 +11,10 @@
|
|||||||
#include "testing/gmock/include/gmock/gmock.h"
|
#include "testing/gmock/include/gmock/gmock.h"
|
||||||
#include "testing/gtest/include/gtest/gtest.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/scoped_ptr.h"
|
||||||
#include "webrtc/system_wrappers/interface/tick_util.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::_;
|
||||||
using ::testing::AnyNumber;
|
using ::testing::AnyNumber;
|
||||||
@ -27,12 +28,12 @@ class MockReceiver : public PacketReceiver {
|
|||||||
MockReceiver() {}
|
MockReceiver() {}
|
||||||
virtual ~MockReceiver() {}
|
virtual ~MockReceiver() {}
|
||||||
|
|
||||||
void IncomingPacket(uint8_t* data, int length) {
|
void IncomingPacket(const uint8_t* data, size_t length) {
|
||||||
IncomingData(data, length);
|
DeliverPacket(data, length);
|
||||||
delete [] data;
|
delete [] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOCK_METHOD2(IncomingData, void(uint8_t*, int));
|
MOCK_METHOD2(DeliverPacket, bool(const uint8_t*, size_t));
|
||||||
};
|
};
|
||||||
|
|
||||||
class FakeNetworkPipeTest : public ::testing::Test {
|
class FakeNetworkPipeTest : public ::testing::Test {
|
||||||
@ -63,11 +64,11 @@ void DeleteMemory(uint8_t* data, int length) { delete [] data; }
|
|||||||
|
|
||||||
// Test the capacity link and verify we get as many packets as we expect.
|
// Test the capacity link and verify we get as many packets as we expect.
|
||||||
TEST_F(FakeNetworkPipeTest, CapacityTest) {
|
TEST_F(FakeNetworkPipeTest, CapacityTest) {
|
||||||
FakeNetworkPipe::Configuration config;
|
FakeNetworkPipe::Config config;
|
||||||
config.packet_receiver = receiver_.get();
|
|
||||||
config.queue_length = 20;
|
config.queue_length = 20;
|
||||||
config.link_capacity_kbps = 80;
|
config.link_capacity_kbps = 80;
|
||||||
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
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
|
// Add 10 packets of 1000 bytes, = 80 kb, and verify it takes one second to
|
||||||
// get through the pipe.
|
// get through the pipe.
|
||||||
@ -80,37 +81,37 @@ TEST_F(FakeNetworkPipeTest, CapacityTest) {
|
|||||||
kPacketSize);
|
kPacketSize);
|
||||||
|
|
||||||
// Time haven't increased yet, so we souldn't get any packets.
|
// Time haven't increased yet, so we souldn't get any packets.
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(0);
|
.Times(0);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
|
|
||||||
// Advance enough time to release one packet.
|
// Advance enough time to release one packet.
|
||||||
TickTime::AdvanceFakeClock(kPacketTimeMs);
|
TickTime::AdvanceFakeClock(kPacketTimeMs);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
|
|
||||||
// Release all but one packet
|
// Release all but one packet
|
||||||
TickTime::AdvanceFakeClock(9 * kPacketTimeMs - 1);
|
TickTime::AdvanceFakeClock(9 * kPacketTimeMs - 1);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(8);
|
.Times(8);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
|
|
||||||
// And the last one.
|
// And the last one.
|
||||||
TickTime::AdvanceFakeClock(1);
|
TickTime::AdvanceFakeClock(1);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the extra network delay.
|
// Test the extra network delay.
|
||||||
TEST_F(FakeNetworkPipeTest, ExtraDelayTest) {
|
TEST_F(FakeNetworkPipeTest, ExtraDelayTest) {
|
||||||
FakeNetworkPipe::Configuration config;
|
FakeNetworkPipe::Config config;
|
||||||
config.packet_receiver = receiver_.get();
|
|
||||||
config.queue_length = 20;
|
config.queue_length = 20;
|
||||||
config.queue_delay_ms = 100;
|
config.queue_delay_ms = 100;
|
||||||
config.link_capacity_kbps = 80;
|
config.link_capacity_kbps = 80;
|
||||||
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
||||||
|
pipe->SetReceiver(receiver_.get());
|
||||||
|
|
||||||
const int kNumPackets = 2;
|
const int kNumPackets = 2;
|
||||||
const int kPacketSize = 1000;
|
const int kPacketSize = 1000;
|
||||||
@ -122,31 +123,31 @@ TEST_F(FakeNetworkPipeTest, ExtraDelayTest) {
|
|||||||
|
|
||||||
// Increase more than kPacketTimeMs, but not more than the extra delay.
|
// Increase more than kPacketTimeMs, but not more than the extra delay.
|
||||||
TickTime::AdvanceFakeClock(kPacketTimeMs);
|
TickTime::AdvanceFakeClock(kPacketTimeMs);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(0);
|
.Times(0);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
|
|
||||||
// Advance the network delay to get the first packet.
|
// Advance the network delay to get the first packet.
|
||||||
TickTime::AdvanceFakeClock(config.queue_delay_ms);
|
TickTime::AdvanceFakeClock(config.queue_delay_ms);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
|
|
||||||
// Advance one more kPacketTimeMs to get the last packet.
|
// Advance one more kPacketTimeMs to get the last packet.
|
||||||
TickTime::AdvanceFakeClock(kPacketTimeMs);
|
TickTime::AdvanceFakeClock(kPacketTimeMs);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(1);
|
.Times(1);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test the number of buffers and packets are dropped when sending too many
|
// Test the number of buffers and packets are dropped when sending too many
|
||||||
// packets too quickly.
|
// packets too quickly.
|
||||||
TEST_F(FakeNetworkPipeTest, QueueLengthTest) {
|
TEST_F(FakeNetworkPipeTest, QueueLengthTest) {
|
||||||
FakeNetworkPipe::Configuration config;
|
FakeNetworkPipe::Config config;
|
||||||
config.packet_receiver = receiver_.get();
|
|
||||||
config.queue_length = 2;
|
config.queue_length = 2;
|
||||||
config.link_capacity_kbps = 80;
|
config.link_capacity_kbps = 80;
|
||||||
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
||||||
|
pipe->SetReceiver(receiver_.get());
|
||||||
|
|
||||||
const int kPacketSize = 1000;
|
const int kPacketSize = 1000;
|
||||||
const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps,
|
const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps,
|
||||||
@ -158,19 +159,19 @@ TEST_F(FakeNetworkPipeTest, QueueLengthTest) {
|
|||||||
// Increase time enough to deliver all three packets, verify only two are
|
// Increase time enough to deliver all three packets, verify only two are
|
||||||
// delivered.
|
// delivered.
|
||||||
TickTime::AdvanceFakeClock(3 * kPacketTimeMs);
|
TickTime::AdvanceFakeClock(3 * kPacketTimeMs);
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(2);
|
.Times(2);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test we get statistics as expected.
|
// Test we get statistics as expected.
|
||||||
TEST_F(FakeNetworkPipeTest, StatisticsTest) {
|
TEST_F(FakeNetworkPipeTest, StatisticsTest) {
|
||||||
FakeNetworkPipe::Configuration config;
|
FakeNetworkPipe::Config config;
|
||||||
config.packet_receiver = receiver_.get();
|
|
||||||
config.queue_length = 2;
|
config.queue_length = 2;
|
||||||
config.queue_delay_ms = 20;
|
config.queue_delay_ms = 20;
|
||||||
config.link_capacity_kbps = 80;
|
config.link_capacity_kbps = 80;
|
||||||
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
scoped_ptr<FakeNetworkPipe> pipe(new FakeNetworkPipe(config));
|
||||||
|
pipe->SetReceiver(receiver_.get());
|
||||||
|
|
||||||
const int kPacketSize = 1000;
|
const int kPacketSize = 1000;
|
||||||
const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps,
|
const int kPacketTimeMs = PacketTimeMs(config.link_capacity_kbps,
|
||||||
@ -180,15 +181,15 @@ TEST_F(FakeNetworkPipeTest, StatisticsTest) {
|
|||||||
SendPackets(pipe.get(), 3, kPacketSize);
|
SendPackets(pipe.get(), 3, kPacketSize);
|
||||||
TickTime::AdvanceFakeClock(3 * kPacketTimeMs + config.queue_delay_ms);
|
TickTime::AdvanceFakeClock(3 * kPacketTimeMs + config.queue_delay_ms);
|
||||||
|
|
||||||
EXPECT_CALL(*receiver_, IncomingData(_, _))
|
EXPECT_CALL(*receiver_, DeliverPacket(_, _))
|
||||||
.Times(2);
|
.Times(2);
|
||||||
pipe->NetworkProcess();
|
pipe->Process();
|
||||||
|
|
||||||
// Packet 1: kPacketTimeMs + config.queue_delay_ms,
|
// Packet 1: kPacketTimeMs + config.queue_delay_ms,
|
||||||
// packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average.
|
// packet 2: 2 * kPacketTimeMs + config.queue_delay_ms => 170 ms average.
|
||||||
EXPECT_EQ(pipe->AverageDelay(), 170);
|
EXPECT_EQ(pipe->AverageDelay(), 170);
|
||||||
EXPECT_EQ(pipe->sent_packets(), 2);
|
EXPECT_EQ(pipe->sent_packets(), 2u);
|
||||||
EXPECT_EQ(pipe->dropped_packets(), 1);
|
EXPECT_EQ(pipe->dropped_packets(), 1u);
|
||||||
EXPECT_EQ(pipe->PercentageLoss(), 1/3.f);
|
EXPECT_EQ(pipe->PercentageLoss(), 1/3.f);
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,8 @@ class RtpRtcpObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RtpRtcpObserver(unsigned int event_timeout_ms, int delay_ms)
|
RtpRtcpObserver(unsigned int event_timeout_ms,
|
||||||
|
const FakeNetworkPipe::Config& configuration)
|
||||||
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
|
: lock_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
observation_complete_(EventWrapper::Create()),
|
observation_complete_(EventWrapper::Create()),
|
||||||
parser_(RtpHeaderParser::Create()),
|
parser_(RtpHeaderParser::Create()),
|
||||||
@ -57,12 +58,12 @@ class RtpRtcpObserver {
|
|||||||
this,
|
this,
|
||||||
&RtpRtcpObserver::OnSendRtp,
|
&RtpRtcpObserver::OnSendRtp,
|
||||||
&RtpRtcpObserver::OnSendRtcp,
|
&RtpRtcpObserver::OnSendRtcp,
|
||||||
delay_ms),
|
configuration),
|
||||||
receive_transport_(lock_.get(),
|
receive_transport_(lock_.get(),
|
||||||
this,
|
this,
|
||||||
&RtpRtcpObserver::OnReceiveRtp,
|
&RtpRtcpObserver::OnReceiveRtp,
|
||||||
&RtpRtcpObserver::OnReceiveRtcp,
|
&RtpRtcpObserver::OnReceiveRtcp,
|
||||||
delay_ms),
|
configuration),
|
||||||
timeout_ms_(event_timeout_ms) {}
|
timeout_ms_(event_timeout_ms) {}
|
||||||
|
|
||||||
explicit RtpRtcpObserver(unsigned int event_timeout_ms)
|
explicit RtpRtcpObserver(unsigned int event_timeout_ms)
|
||||||
@ -73,12 +74,12 @@ class RtpRtcpObserver {
|
|||||||
this,
|
this,
|
||||||
&RtpRtcpObserver::OnSendRtp,
|
&RtpRtcpObserver::OnSendRtp,
|
||||||
&RtpRtcpObserver::OnSendRtcp,
|
&RtpRtcpObserver::OnSendRtcp,
|
||||||
0),
|
FakeNetworkPipe::Config()),
|
||||||
receive_transport_(lock_.get(),
|
receive_transport_(lock_.get(),
|
||||||
this,
|
this,
|
||||||
&RtpRtcpObserver::OnReceiveRtp,
|
&RtpRtcpObserver::OnReceiveRtp,
|
||||||
&RtpRtcpObserver::OnReceiveRtcp,
|
&RtpRtcpObserver::OnReceiveRtcp,
|
||||||
0),
|
FakeNetworkPipe::Config()),
|
||||||
timeout_ms_(event_timeout_ms) {}
|
timeout_ms_(event_timeout_ms) {}
|
||||||
|
|
||||||
enum Action {
|
enum Action {
|
||||||
@ -113,8 +114,8 @@ class RtpRtcpObserver {
|
|||||||
RtpRtcpObserver* observer,
|
RtpRtcpObserver* observer,
|
||||||
PacketTransportAction on_rtp,
|
PacketTransportAction on_rtp,
|
||||||
PacketTransportAction on_rtcp,
|
PacketTransportAction on_rtcp,
|
||||||
int delay_ms)
|
const FakeNetworkPipe::Config& configuration)
|
||||||
: test::DirectTransport(delay_ms),
|
: test::DirectTransport(configuration),
|
||||||
lock_(lock),
|
lock_(lock),
|
||||||
observer_(observer),
|
observer_(observer),
|
||||||
on_rtp_(on_rtp),
|
on_rtp_(on_rtp),
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
'fake_decoder.h',
|
'fake_decoder.h',
|
||||||
'fake_encoder.cc',
|
'fake_encoder.cc',
|
||||||
'fake_encoder.h',
|
'fake_encoder.h',
|
||||||
|
'fake_network_pipe.cc',
|
||||||
|
'fake_network_pipe.h',
|
||||||
'flags.cc',
|
'flags.cc',
|
||||||
'flags.h',
|
'flags.h',
|
||||||
'frame_generator_capturer.cc',
|
'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
|
||||||
}
|
}
|
||||||
|
@ -49,8 +49,8 @@ class CallPerfTest : public ::testing::Test {
|
|||||||
|
|
||||||
class SyncRtcpObserver : public test::RtpRtcpObserver {
|
class SyncRtcpObserver : public test::RtpRtcpObserver {
|
||||||
public:
|
public:
|
||||||
explicit SyncRtcpObserver(int delay_ms)
|
explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config)
|
||||||
: test::RtpRtcpObserver(kLongTimeoutMs, delay_ms),
|
: test::RtpRtcpObserver(kLongTimeoutMs, config),
|
||||||
critical_section_(CriticalSectionWrapper::CreateCriticalSection()) {}
|
critical_section_(CriticalSectionWrapper::CreateCriticalSection()) {}
|
||||||
|
|
||||||
virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
|
virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||||
@ -119,7 +119,7 @@ class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
|
|||||||
int voe_channel,
|
int voe_channel,
|
||||||
VoEVideoSync* voe_sync,
|
VoEVideoSync* voe_sync,
|
||||||
SyncRtcpObserver* audio_observer)
|
SyncRtcpObserver* audio_observer)
|
||||||
: SyncRtcpObserver(0),
|
: SyncRtcpObserver(FakeNetworkPipe::Config()),
|
||||||
clock_(clock),
|
clock_(clock),
|
||||||
voe_channel_(voe_channel),
|
voe_channel_(voe_channel),
|
||||||
voe_sync_(voe_sync),
|
voe_sync_(voe_sync),
|
||||||
@ -189,8 +189,9 @@ TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) {
|
|||||||
EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
|
EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
|
||||||
int channel = voe_base->CreateChannel();
|
int channel = voe_base->CreateChannel();
|
||||||
|
|
||||||
const int kVoiceDelayMs = 500;
|
FakeNetworkPipe::Config net_config;
|
||||||
SyncRtcpObserver audio_observer(kVoiceDelayMs);
|
net_config.queue_delay_ms = 500;
|
||||||
|
SyncRtcpObserver audio_observer(net_config);
|
||||||
VideoRtcpAndSyncObserver observer(
|
VideoRtcpAndSyncObserver observer(
|
||||||
Clock::GetRealTimeClock(), channel, voe_sync, &audio_observer);
|
Clock::GetRealTimeClock(), channel, voe_sync, &audio_observer);
|
||||||
|
|
||||||
|
@ -28,14 +28,12 @@
|
|||||||
'helpers/vie_to_file_renderer.cc',
|
'helpers/vie_to_file_renderer.cc',
|
||||||
|
|
||||||
# Testbed classes
|
# Testbed classes
|
||||||
'include/fake_network_pipe.h',
|
|
||||||
'include/tb_capture_device.h',
|
'include/tb_capture_device.h',
|
||||||
'include/tb_external_transport.h',
|
'include/tb_external_transport.h',
|
||||||
'include/tb_I420_codec.h',
|
'include/tb_I420_codec.h',
|
||||||
'include/tb_interfaces.h',
|
'include/tb_interfaces.h',
|
||||||
'include/tb_video_channel.h',
|
'include/tb_video_channel.h',
|
||||||
|
|
||||||
'testbed/fake_network_pipe.cc',
|
|
||||||
'testbed/tb_capture_device.cc',
|
'testbed/tb_capture_device.cc',
|
||||||
'testbed/tb_external_transport.cc',
|
'testbed/tb_external_transport.cc',
|
||||||
'testbed/tb_I420_codec.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
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
@ -43,6 +43,7 @@
|
|||||||
'system_wrappers/source/system_wrappers_tests.gyp:*',
|
'system_wrappers/source/system_wrappers_tests.gyp:*',
|
||||||
'test/metrics.gyp:*',
|
'test/metrics.gyp:*',
|
||||||
'test/test.gyp:*',
|
'test/test.gyp:*',
|
||||||
|
'test/webrtc_test_common.gyp:webrtc_test_common_unittests',
|
||||||
'tools/tools.gyp:*',
|
'tools/tools.gyp:*',
|
||||||
'webrtc_tests',
|
'webrtc_tests',
|
||||||
],
|
],
|
||||||
|
Reference in New Issue
Block a user