Adding an end-to-end connection time test.

The test uses a fake clock and simulates network and signaling delays in
order to get a repeatable measurement of the time to establish a
connection (including DTLS). This will help ensure that various
optimizations continue to work as expected, and no new delays are
introduced.

This CL depends on: https://codereview.webrtc.org/2140283002/

R=honghaiz@webrtc.org, pthatcher@webrtc.org, skvlad@webrtc.org

Review URL: https://codereview.webrtc.org/2141863003 .

Cr-Commit-Position: refs/heads/master@{#14270}
This commit is contained in:
Taylor Brandstetter 2016-09-16 15:07:50 -07:00
parent de65ddc212
commit e5835f5d84
3 changed files with 286 additions and 79 deletions

View File

@ -30,6 +30,7 @@
#include "webrtc/api/test/fakertccertificategenerator.h"
#include "webrtc/api/test/fakevideotrackrenderer.h"
#include "webrtc/api/test/mockpeerconnectionobservers.h"
#include "webrtc/base/fakenetwork.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/helpers.h"
#include "webrtc/base/physicalsocketserver.h"
@ -38,9 +39,10 @@
#include "webrtc/base/thread.h"
#include "webrtc/base/virtualsocketserver.h"
#include "webrtc/media/engine/fakewebrtcvideoengine.h"
#include "webrtc/p2p/base/fakeportallocator.h"
#include "webrtc/p2p/base/p2pconstants.h"
#include "webrtc/p2p/base/sessiondescription.h"
#include "webrtc/p2p/base/testturnserver.h"
#include "webrtc/p2p/client/basicportallocator.h"
#include "webrtc/pc/mediasession.h"
#define MAYBE_SKIP_TEST(feature) \
@ -104,6 +106,20 @@ static const int kDefaultSrtpCryptoSuite = rtc::SRTP_AES128_CM_SHA1_32;
static const int kDefaultSrtpCryptoSuiteGcm = rtc::SRTP_AEAD_AES_256_GCM;
#endif
// Used to simulate signaling ICE/SDP between two PeerConnections.
enum Message { MSG_SDP_MESSAGE, MSG_ICE_MESSAGE };
struct SdpMessage {
std::string type;
std::string msg;
};
struct IceMessage {
std::string sdp_mid;
int sdp_mline_index;
std::string msg;
};
static void RemoveLinesFromSdp(const std::string& line_start,
std::string* sdp) {
const char kSdpLineEnd[] = "\r\n";
@ -169,13 +185,15 @@ class MockRtpReceiverObserver : public webrtc::RtpReceiverObserverInterface {
class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
public SignalingMessageReceiver,
public ObserverInterface {
public ObserverInterface,
public rtc::MessageHandler {
public:
// If |config| is not provided, uses a default constructed RTCConfiguration.
static PeerConnectionTestClient* CreateClientWithDtlsIdentityStore(
const std::string& id,
const MediaConstraintsInterface* constraints,
const PeerConnectionFactory::Options* options,
const PeerConnectionInterface::RTCConfiguration& config,
const PeerConnectionInterface::RTCConfiguration* config,
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
bool prefer_constraint_apis,
rtc::Thread* network_thread,
@ -193,7 +211,7 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
const std::string& id,
const MediaConstraintsInterface* constraints,
const PeerConnectionFactory::Options* options,
const PeerConnectionInterface::RTCConfiguration& config,
const PeerConnectionInterface::RTCConfiguration* config,
rtc::Thread* network_thread,
rtc::Thread* worker_thread) {
std::unique_ptr<FakeRTCCertificateGenerator> cert_generator(
@ -208,14 +226,13 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
static PeerConnectionTestClient* CreateClientPreferNoConstraints(
const std::string& id,
const PeerConnectionFactory::Options* options,
const PeerConnectionInterface::RTCConfiguration& config,
rtc::Thread* network_thread,
rtc::Thread* worker_thread) {
std::unique_ptr<FakeRTCCertificateGenerator> cert_generator(
rtc::SSLStreamAdapter::HaveDtlsSrtp() ?
new FakeRTCCertificateGenerator() : nullptr);
return CreateClientWithDtlsIdentityStore(id, nullptr, options, config,
return CreateClientWithDtlsIdentityStore(id, nullptr, options, nullptr,
std::move(cert_generator), false,
network_thread, worker_thread);
}
@ -239,8 +256,64 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
std::string sdp;
EXPECT_TRUE(offer->ToString(&sdp));
EXPECT_TRUE(DoSetLocalDescription(offer.release()));
signaling_message_receiver_->ReceiveSdpMessage(
webrtc::SessionDescriptionInterface::kOffer, sdp);
SendSdpMessage(webrtc::SessionDescriptionInterface::kOffer, sdp);
}
void SendSdpMessage(const std::string& type, std::string& msg) {
if (signaling_delay_ms_ == 0) {
if (signaling_message_receiver_) {
signaling_message_receiver_->ReceiveSdpMessage(type, msg);
}
} else {
rtc::Thread::Current()->PostDelayed(
RTC_FROM_HERE, signaling_delay_ms_, this, MSG_SDP_MESSAGE,
new rtc::TypedMessageData<SdpMessage>({type, msg}));
}
}
void SendIceMessage(const std::string& sdp_mid,
int sdp_mline_index,
const std::string& msg) {
if (signaling_delay_ms_ == 0) {
if (signaling_message_receiver_) {
signaling_message_receiver_->ReceiveIceMessage(sdp_mid, sdp_mline_index,
msg);
}
} else {
rtc::Thread::Current()->PostDelayed(RTC_FROM_HERE, signaling_delay_ms_,
this, MSG_ICE_MESSAGE,
new rtc::TypedMessageData<IceMessage>(
{sdp_mid, sdp_mline_index, msg}));
}
}
// MessageHandler callback.
void OnMessage(rtc::Message* msg) override {
switch (msg->message_id) {
case MSG_SDP_MESSAGE: {
auto sdp_message =
static_cast<rtc::TypedMessageData<SdpMessage>*>(msg->pdata);
if (signaling_message_receiver_) {
signaling_message_receiver_->ReceiveSdpMessage(
sdp_message->data().type, sdp_message->data().msg);
}
delete sdp_message;
break;
}
case MSG_ICE_MESSAGE: {
auto ice_message =
static_cast<rtc::TypedMessageData<IceMessage>*>(msg->pdata);
if (signaling_message_receiver_) {
signaling_message_receiver_->ReceiveIceMessage(
ice_message->data().sdp_mid, ice_message->data().sdp_mline_index,
ice_message->data().msg);
}
delete ice_message;
break;
}
default:
RTC_CHECK(false);
}
}
// SignalingMessageReceiver callback.
@ -299,8 +372,7 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
// Remote party may be deleted.
return;
}
signaling_message_receiver_->ReceiveIceMessage(
candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp);
SendIceMessage(candidate->sdp_mid(), candidate->sdp_mline_index(), ice_sdp);
}
// MediaStreamInterface callback
@ -375,6 +447,8 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
signaling_message_receiver_ = signaling_message_receiver;
}
void set_signaling_delay_ms(int delay_ms) { signaling_delay_ms_ = delay_ms; }
void EnableVideoDecoderFactory() {
video_decoder_factory_enabled_ = true;
fake_video_decoder_factory_->AddSupportedVideoCodecType(
@ -402,6 +476,9 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
bool ExpectIceRenomination() { return expect_ice_renomination_; }
bool ExpectRemoteIceRenomination() { return expect_remote_ice_renomination_; }
// The below 3 methods assume streams will be offered.
// Thus they'll only set the "offer to receive" flag to true if it's
// currently false, not if it's just unset.
void SetReceiveAudioVideo(bool audio, bool video) {
SetReceiveAudio(audio);
SetReceiveVideo(video);
@ -410,15 +487,24 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
}
void SetReceiveAudio(bool audio) {
if (audio && can_receive_audio())
if (audio && can_receive_audio()) {
return;
}
offer_answer_constraints_.SetMandatoryReceiveAudio(audio);
offer_answer_options_.offer_to_receive_audio = audio ? 1 : 0;
}
void SetReceiveVideo(bool video) {
if (video && can_receive_video())
if (video && can_receive_video()) {
return;
}
offer_answer_constraints_.SetMandatoryReceiveVideo(video);
offer_answer_options_.offer_to_receive_video = video ? 1 : 0;
}
void SetOfferToReceiveAudioVideo(bool audio, bool video) {
offer_answer_constraints_.SetMandatoryReceiveAudio(audio);
offer_answer_options_.offer_to_receive_audio = audio ? 1 : 0;
offer_answer_constraints_.SetMandatoryReceiveVideo(video);
offer_answer_options_.offer_to_receive_video = video ? 1 : 0;
}
@ -896,7 +982,7 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
bool Init(
const MediaConstraintsInterface* constraints,
const PeerConnectionFactory::Options* options,
const PeerConnectionInterface::RTCConfiguration& config,
const PeerConnectionInterface::RTCConfiguration* config,
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
bool prefer_constraint_apis,
rtc::Thread* network_thread,
@ -908,8 +994,11 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
}
prefer_constraint_apis_ = prefer_constraint_apis;
fake_network_manager_.reset(new rtc::FakeNetworkManager());
fake_network_manager_->AddInterface(rtc::SocketAddress("192.168.1.1", 0));
std::unique_ptr<cricket::PortAllocator> port_allocator(
new cricket::FakePortAllocator(network_thread, nullptr));
new cricket::BasicPortAllocator(fake_network_manager_.get()));
fake_audio_capture_module_ = FakeAudioCaptureModule::Create();
if (fake_audio_capture_module_ == nullptr) {
@ -931,17 +1020,23 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
peer_connection_ =
CreatePeerConnection(std::move(port_allocator), constraints, config,
std::move(cert_generator));
return peer_connection_.get() != nullptr;
}
rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(
std::unique_ptr<cricket::PortAllocator> port_allocator,
const MediaConstraintsInterface* constraints,
const PeerConnectionInterface::RTCConfiguration& config,
const PeerConnectionInterface::RTCConfiguration* config,
std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator) {
// CreatePeerConnection with RTCConfiguration.
PeerConnectionInterface::RTCConfiguration default_config;
if (!config) {
config = &default_config;
}
return peer_connection_factory_->CreatePeerConnection(
config, constraints, std::move(port_allocator),
*config, constraints, std::move(port_allocator),
std::move(cert_generator), this);
}
@ -961,10 +1056,7 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
std::string sdp;
EXPECT_TRUE(answer->ToString(&sdp));
EXPECT_TRUE(DoSetLocalDescription(answer.release()));
if (signaling_message_receiver_) {
signaling_message_receiver_->ReceiveSdpMessage(
webrtc::SessionDescriptionInterface::kAnswer, sdp);
}
SendSdpMessage(webrtc::SessionDescriptionInterface::kAnswer, sdp);
}
void HandleIncomingAnswer(const std::string& msg) {
@ -1065,6 +1157,8 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
std::string id_;
std::unique_ptr<rtc::FakeNetworkManager> fake_network_manager_;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
peer_connection_factory_;
@ -1095,6 +1189,7 @@ class PeerConnectionTestClient : public webrtc::PeerConnectionObserver,
// For remote peer communication.
SignalingMessageReceiver* signaling_message_receiver_ = nullptr;
int signaling_delay_ms_ = 0;
// Store references to the video capturers we've created, so that we can stop
// them, if required.
@ -1129,9 +1224,6 @@ class P2PTestConductor : public testing::Test {
worker_thread_(rtc::Thread::Create()) {
RTC_CHECK(network_thread_->Start());
RTC_CHECK(worker_thread_->Start());
webrtc::PeerConnectionInterface::IceServer ice_server;
ice_server.uri = "stun:stun.l.google.com:19302";
config_.servers.push_back(ice_server);
}
bool SessionActive() {
@ -1234,19 +1326,24 @@ class P2PTestConductor : public testing::Test {
bool CreateTestClients(MediaConstraintsInterface* init_constraints,
MediaConstraintsInterface* recv_constraints) {
return CreateTestClients(init_constraints, nullptr, recv_constraints,
nullptr);
return CreateTestClients(init_constraints, nullptr, nullptr,
recv_constraints, nullptr, nullptr);
}
bool CreateTestClients(
const PeerConnectionInterface::RTCConfiguration& init_config,
const PeerConnectionInterface::RTCConfiguration& recv_config) {
return CreateTestClients(nullptr, nullptr, &init_config, nullptr, nullptr,
&recv_config);
}
bool CreateTestClientsThatPreferNoConstraints() {
initiating_client_.reset(
PeerConnectionTestClient::CreateClientPreferNoConstraints(
"Caller: ", nullptr, config_, network_thread_.get(),
worker_thread_.get()));
"Caller: ", nullptr, network_thread_.get(), worker_thread_.get()));
receiving_client_.reset(
PeerConnectionTestClient::CreateClientPreferNoConstraints(
"Callee: ", nullptr, config_, network_thread_.get(),
worker_thread_.get()));
"Callee: ", nullptr, network_thread_.get(), worker_thread_.get()));
if (!initiating_client_ || !receiving_client_) {
return false;
}
@ -1256,20 +1353,18 @@ class P2PTestConductor : public testing::Test {
return true;
}
void SetSignalingReceivers() {
initiating_client_->set_signaling_message_receiver(receiving_client_.get());
receiving_client_->set_signaling_message_receiver(initiating_client_.get());
}
bool CreateTestClients(MediaConstraintsInterface* init_constraints,
PeerConnectionFactory::Options* init_options,
MediaConstraintsInterface* recv_constraints,
PeerConnectionFactory::Options* recv_options) {
bool CreateTestClients(
MediaConstraintsInterface* init_constraints,
PeerConnectionFactory::Options* init_options,
const PeerConnectionInterface::RTCConfiguration* init_config,
MediaConstraintsInterface* recv_constraints,
PeerConnectionFactory::Options* recv_options,
const PeerConnectionInterface::RTCConfiguration* recv_config) {
initiating_client_.reset(PeerConnectionTestClient::CreateClient(
"Caller: ", init_constraints, init_options, config_,
"Caller: ", init_constraints, init_options, init_config,
network_thread_.get(), worker_thread_.get()));
receiving_client_.reset(PeerConnectionTestClient::CreateClient(
"Callee: ", recv_constraints, recv_options, config_,
"Callee: ", recv_constraints, recv_options, recv_config,
network_thread_.get(), worker_thread_.get()));
if (!initiating_client_ || !receiving_client_) {
return false;
@ -1278,6 +1373,16 @@ class P2PTestConductor : public testing::Test {
return true;
}
void SetSignalingReceivers() {
initiating_client_->set_signaling_message_receiver(receiving_client_.get());
receiving_client_->set_signaling_message_receiver(initiating_client_.get());
}
void SetSignalingDelayMs(int delay_ms) {
initiating_client_->set_signaling_delay_ms(delay_ms);
receiving_client_->set_signaling_delay_ms(delay_ms);
}
void SetVideoConstraints(const webrtc::FakeConstraints& init_constraints,
const webrtc::FakeConstraints& recv_constraints) {
initiating_client_->SetVideoConstraints(init_constraints);
@ -1370,7 +1475,7 @@ class P2PTestConductor : public testing::Test {
// Make sure the new client is using a different certificate.
return PeerConnectionTestClient::CreateClientWithDtlsIdentityStore(
"New Peer: ", &setup_constraints, nullptr, config_,
"New Peer: ", &setup_constraints, nullptr, nullptr,
std::move(cert_generator), prefer_constraint_apis_,
network_thread_.get(), worker_thread_.get());
}
@ -1385,6 +1490,8 @@ class P2PTestConductor : public testing::Test {
}
}
rtc::Thread* network_thread() { return network_thread_.get(); }
rtc::VirtualSocketServer* virtual_socket_server() { return ss_.get(); }
PeerConnectionTestClient* initializing_client() {
@ -1412,9 +1519,6 @@ class P2PTestConductor : public testing::Test {
receiving_client_.reset(client);
return old;
}
webrtc::PeerConnectionInterface::RTCConfiguration* config() {
return &config_;
}
bool AllObserversReceived(
const std::vector<std::unique_ptr<MockRtpReceiverObserver>>& observers) {
@ -1432,8 +1536,8 @@ class P2PTestConductor : public testing::Test {
init_options.crypto_options.enable_gcm_crypto_suites = local_gcm_enabled;
PeerConnectionFactory::Options recv_options;
recv_options.crypto_options.enable_gcm_crypto_suites = remote_gcm_enabled;
ASSERT_TRUE(
CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
&recv_options, nullptr));
rtc::scoped_refptr<webrtc::FakeMetricsObserver>
init_observer =
new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
@ -1460,7 +1564,6 @@ class P2PTestConductor : public testing::Test {
std::unique_ptr<PeerConnectionTestClient> initiating_client_;
std::unique_ptr<PeerConnectionTestClient> receiving_client_;
bool prefer_constraint_apis_ = true;
webrtc::PeerConnectionInterface::RTCConfiguration config_;
};
// Disable for TSan v2, see
@ -1803,8 +1906,8 @@ TEST_F(P2PTestConductor, GetDtls12None) {
init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
PeerConnectionFactory::Options recv_options;
recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
ASSERT_TRUE(
CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
&recv_options, nullptr));
rtc::scoped_refptr<webrtc::FakeMetricsObserver>
init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
initializing_client()->pc()->RegisterUMAObserver(init_observer);
@ -1828,8 +1931,8 @@ TEST_F(P2PTestConductor, GetDtls12Both) {
init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
PeerConnectionFactory::Options recv_options;
recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
ASSERT_TRUE(
CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
&recv_options, nullptr));
rtc::scoped_refptr<webrtc::FakeMetricsObserver>
init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
initializing_client()->pc()->RegisterUMAObserver(init_observer);
@ -1854,8 +1957,8 @@ TEST_F(P2PTestConductor, GetDtls12Init) {
init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
PeerConnectionFactory::Options recv_options;
recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
ASSERT_TRUE(
CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
&recv_options, nullptr));
rtc::scoped_refptr<webrtc::FakeMetricsObserver>
init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
initializing_client()->pc()->RegisterUMAObserver(init_observer);
@ -1880,8 +1983,8 @@ TEST_F(P2PTestConductor, GetDtls12Recv) {
init_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_10;
PeerConnectionFactory::Options recv_options;
recv_options.ssl_max_version = rtc::SSL_PROTOCOL_DTLS_12;
ASSERT_TRUE(
CreateTestClients(nullptr, &init_options, nullptr, &recv_options));
ASSERT_TRUE(CreateTestClients(nullptr, &init_options, nullptr, nullptr,
&recv_options, nullptr));
rtc::scoped_refptr<webrtc::FakeMetricsObserver>
init_observer = new rtc::RefCountedObject<webrtc::FakeMetricsObserver>();
initializing_client()->pc()->RegisterUMAObserver(init_observer);
@ -2176,8 +2279,9 @@ TEST_F(P2PTestConductor, IceRestart) {
}
TEST_F(P2PTestConductor, IceRenominationDisabled) {
config()->enable_ice_renomination = false;
ASSERT_TRUE(CreateTestClients());
PeerConnectionInterface::RTCConfiguration config;
config.enable_ice_renomination = false;
ASSERT_TRUE(CreateTestClients(config, config));
LocalP2PTest();
initializing_client()->VerifyLocalIceRenomination();
@ -2187,8 +2291,9 @@ TEST_F(P2PTestConductor, IceRenominationDisabled) {
}
TEST_F(P2PTestConductor, IceRenominationEnabled) {
config()->enable_ice_renomination = true;
ASSERT_TRUE(CreateTestClients());
PeerConnectionInterface::RTCConfiguration config;
config.enable_ice_renomination = true;
ASSERT_TRUE(CreateTestClients(config, config));
initializing_client()->SetExpectIceRenomination(true);
initializing_client()->SetExpectRemoteIceRenomination(true);
receiving_client()->SetExpectIceRenomination(true);
@ -2268,8 +2373,9 @@ TEST_F(P2PTestConductor, EarlyWarmupTest) {
// This test sets up a call between two parties using QUIC instead of DTLS for
// audio and video, and a QUIC data channel.
TEST_F(P2PTestConductor, LocalP2PTestQuicDataChannel) {
config()->enable_quic = true;
ASSERT_TRUE(CreateTestClients());
PeerConnectionInterface::RTCConfiguration quic_config;
quic_config.enable_quic = true;
ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
webrtc::DataChannelInit init;
init.ordered = false;
init.reliable = true;
@ -2296,7 +2402,9 @@ TEST_F(P2PTestConductor, LocalP2PTestQuicDataChannel) {
// Tests that negotiation of QUIC data channels is completed without error.
TEST_F(P2PTestConductor, NegotiateQuicDataChannel) {
config()->enable_quic = true;
PeerConnectionInterface::RTCConfiguration quic_config;
quic_config.enable_quic = true;
ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
FakeConstraints constraints;
constraints.SetMandatory(MediaConstraintsInterface::kEnableDtlsSrtp, true);
ASSERT_TRUE(CreateTestClients(&constraints, &constraints));
@ -2310,16 +2418,18 @@ TEST_F(P2PTestConductor, NegotiateQuicDataChannel) {
// This test sets up a JSEP call using QUIC. The callee only receives video.
TEST_F(P2PTestConductor, LocalP2PTestVideoOnlyWithQuic) {
config()->enable_quic = true;
ASSERT_TRUE(CreateTestClients());
PeerConnectionInterface::RTCConfiguration quic_config;
quic_config.enable_quic = true;
ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
receiving_client()->SetReceiveAudioVideo(false, true);
LocalP2PTest();
}
// This test sets up a JSEP call using QUIC. The callee only receives audio.
TEST_F(P2PTestConductor, LocalP2PTestAudioOnlyWithQuic) {
config()->enable_quic = true;
ASSERT_TRUE(CreateTestClients());
PeerConnectionInterface::RTCConfiguration quic_config;
quic_config.enable_quic = true;
ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
receiving_client()->SetReceiveAudioVideo(true, false);
LocalP2PTest();
}
@ -2327,8 +2437,9 @@ TEST_F(P2PTestConductor, LocalP2PTestAudioOnlyWithQuic) {
// This test sets up a JSEP call using QUIC. The callee rejects both audio and
// video.
TEST_F(P2PTestConductor, LocalP2PTestNoVideoAudioWithQuic) {
config()->enable_quic = true;
ASSERT_TRUE(CreateTestClients());
PeerConnectionInterface::RTCConfiguration quic_config;
quic_config.enable_quic = true;
ASSERT_TRUE(CreateTestClients(quic_config, quic_config));
receiving_client()->SetReceiveAudioVideo(false, false);
LocalP2PTest();
}
@ -2368,6 +2479,102 @@ TEST_F(P2PTestConductor, ForwardVideoOnlyStream) {
kMaxWaitForFramesMs);
}
// Test that we achieve the expected end-to-end connection time, using a
// fake clock and simulated latency on the media and signaling paths.
// We use a TURN<->TURN connection because this is usually the quickest to
// set up initially, especially when we're confident the connection will work
// and can start sending media before we get a STUN response.
//
// With various optimizations enabled, here are the network delays we expect to
// be on the critical path:
// 1. 2 signaling trips: Signaling offer and offerer's TURN candidate, then
// signaling answer (with DTLS fingerprint).
// 2. 9 media hops: Rest of the DTLS handshake. 3 hops in each direction when
// using TURN<->TURN pair, and DTLS exchange is 4 packets,
// the first of which should have arrived before the answer.
TEST_F(P2PTestConductor, EndToEndConnectionTimeWithTurnTurnPair) {
rtc::ScopedFakeClock fake_clock;
// Some things use a time of "0" as a special value, so we need to start out
// the fake clock at a nonzero time.
// TODO(deadbeef): Fix this.
fake_clock.AdvanceTime(rtc::TimeDelta::FromSeconds(1));
static constexpr int media_hop_delay_ms = 50;
static constexpr int signaling_trip_delay_ms = 500;
// For explanation of these values, see comment above.
static constexpr int required_media_hops = 9;
static constexpr int required_signaling_trips = 2;
// For internal delays (such as posting an event asychronously).
static constexpr int allowed_internal_delay_ms = 20;
static constexpr int total_connection_time_ms =
media_hop_delay_ms * required_media_hops +
signaling_trip_delay_ms * required_signaling_trips +
allowed_internal_delay_ms;
static const rtc::SocketAddress turn_server_1_internal_address{"88.88.88.0",
3478};
static const rtc::SocketAddress turn_server_1_external_address{"88.88.88.1",
0};
static const rtc::SocketAddress turn_server_2_internal_address{"99.99.99.0",
3478};
static const rtc::SocketAddress turn_server_2_external_address{"99.99.99.1",
0};
cricket::TestTurnServer turn_server_1(network_thread(),
turn_server_1_internal_address,
turn_server_1_external_address);
cricket::TestTurnServer turn_server_2(network_thread(),
turn_server_2_internal_address,
turn_server_2_external_address);
// Bypass permission check on received packets so media can be sent before
// the candidate is signaled.
turn_server_1.set_enable_permission_checks(false);
turn_server_2.set_enable_permission_checks(false);
PeerConnectionInterface::RTCConfiguration client_1_config;
webrtc::PeerConnectionInterface::IceServer ice_server_1;
ice_server_1.urls.push_back("turn:88.88.88.0:3478");
ice_server_1.username = "test";
ice_server_1.password = "test";
client_1_config.servers.push_back(ice_server_1);
client_1_config.type = webrtc::PeerConnectionInterface::kRelay;
client_1_config.presume_writable_when_fully_relayed = true;
PeerConnectionInterface::RTCConfiguration client_2_config;
webrtc::PeerConnectionInterface::IceServer ice_server_2;
ice_server_2.urls.push_back("turn:99.99.99.0:3478");
ice_server_2.username = "test";
ice_server_2.password = "test";
client_2_config.servers.push_back(ice_server_2);
client_2_config.type = webrtc::PeerConnectionInterface::kRelay;
client_2_config.presume_writable_when_fully_relayed = true;
ASSERT_TRUE(CreateTestClients(client_1_config, client_2_config));
// Set up the simulated delays.
SetSignalingDelayMs(signaling_trip_delay_ms);
virtual_socket_server()->set_delay_mean(media_hop_delay_ms);
virtual_socket_server()->UpdateDelayDistribution();
initializing_client()->SetOfferToReceiveAudioVideo(true, true);
initializing_client()->Negotiate();
// TODO(deadbeef): kIceConnectionConnected currently means both ICE and DTLS
// are connected. This is an important distinction. Once we have separate ICE
// and DTLS state, this check needs to use the DTLS state.
EXPECT_TRUE_SIMULATED_WAIT(
(receiving_client()->ice_connection_state() ==
webrtc::PeerConnectionInterface::kIceConnectionConnected ||
receiving_client()->ice_connection_state() ==
webrtc::PeerConnectionInterface::kIceConnectionCompleted) &&
(initializing_client()->ice_connection_state() ==
webrtc::PeerConnectionInterface::kIceConnectionConnected ||
initializing_client()->ice_connection_state() ==
webrtc::PeerConnectionInterface::kIceConnectionCompleted),
total_connection_time_ms, fake_clock);
// Need to free the clients here since they're using things we created on
// the stack.
delete set_initializing_client(nullptr);
delete set_receiving_client(nullptr);
}
class IceServerParsingTest : public testing::Test {
public:
// Convenience for parsing a single URL.

View File

@ -31,7 +31,7 @@ const int kFakeIPv6NetworkPrefixLength = 64;
class FakeNetworkManager : public NetworkManagerBase,
public MessageHandler {
public:
FakeNetworkManager() : thread_(Thread::Current()) {}
FakeNetworkManager() {}
typedef std::vector<std::pair<SocketAddress, AdapterType>> IfaceList;
@ -68,7 +68,7 @@ class FakeNetworkManager : public NetworkManagerBase,
++start_count_;
if (start_count_ == 1) {
sent_first_update_ = false;
thread_->Post(RTC_FROM_HERE, this);
rtc::Thread::Current()->Post(RTC_FROM_HERE, this);
} else {
if (sent_first_update_) {
SignalNetworksChanged();
@ -115,7 +115,6 @@ class FakeNetworkManager : public NetworkManagerBase,
}
}
Thread* thread_;
IfaceList ifaces_;
int next_index_ = 0;
int start_count_ = 0;

View File

@ -52,10 +52,10 @@ class TestTurnServer : public TurnAuthInterface {
const rtc::SocketAddress& int_addr,
const rtc::SocketAddress& udp_ext_addr,
ProtocolType int_protocol = PROTO_UDP)
: server_(thread) {
: server_(thread), thread_(thread) {
AddInternalSocket(int_addr, int_protocol);
server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(),
udp_ext_addr);
server_.SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(thread),
udp_ext_addr);
server_.set_realm(kTestRealm);
server_.set_software(kTestSoftware);
server_.set_auth_hook(this);
@ -77,15 +77,15 @@ class TestTurnServer : public TurnAuthInterface {
void AddInternalSocket(const rtc::SocketAddress& int_addr,
ProtocolType proto) {
rtc::Thread* thread = rtc::Thread::Current();
if (proto == cricket::PROTO_UDP) {
server_.AddInternalSocket(rtc::AsyncUDPSocket::Create(
thread->socketserver(), int_addr), proto);
server_.AddInternalSocket(
rtc::AsyncUDPSocket::Create(thread_->socketserver(), int_addr),
proto);
} else if (proto == cricket::PROTO_TCP) {
// For TCP we need to create a server socket which can listen for incoming
// new connections.
rtc::AsyncSocket* socket =
thread->socketserver()->CreateAsyncSocket(SOCK_STREAM);
thread_->socketserver()->CreateAsyncSocket(SOCK_STREAM);
socket->Bind(int_addr);
socket->Listen(5);
server_.AddInternalServerSocket(socket, proto);
@ -114,6 +114,7 @@ class TestTurnServer : public TurnAuthInterface {
}
TurnServer server_;
rtc::Thread* thread_;
};
} // namespace cricket