This way that emulated network may be injected into PeerConnectionFactoryDependencies and thus would allow test code not to manually create BasicPortAllocator Bug: webrtc:42232556 Change-Id: Ifac29e584e66d7e585e8c8d74959cba288c6ffe0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/376500 Reviewed-by: Artem Titov <titovartem@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#43864}
317 lines
13 KiB
C++
317 lines
13 KiB
C++
/*
|
|
* Copyright 2019 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 <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "api/audio_options.h"
|
|
#include "api/enable_media_with_defaults.h"
|
|
#include "api/jsep.h"
|
|
#include "api/media_stream_interface.h"
|
|
#include "api/peer_connection_interface.h"
|
|
#include "api/rtc_event_log/rtc_event_log_factory.h"
|
|
#include "api/scoped_refptr.h"
|
|
#include "api/task_queue/default_task_queue_factory.h"
|
|
#include "api/test/network_emulation/network_emulation_interfaces.h"
|
|
#include "api/test/network_emulation_manager.h"
|
|
#include "api/test/rtc_error_matchers.h"
|
|
#include "api/test/simulated_network.h"
|
|
#include "api/transport/field_trial_based_config.h"
|
|
#include "modules/audio_device/include/test_audio_device.h"
|
|
#include "p2p/base/port_allocator.h"
|
|
#include "pc/peer_connection_wrapper.h"
|
|
#include "pc/test/mock_peer_connection_observers.h"
|
|
#include "rtc_base/network.h"
|
|
#include "rtc_base/task_queue_for_test.h"
|
|
#include "test/gmock.h"
|
|
#include "test/gtest.h"
|
|
#include "test/network/network_emulation.h"
|
|
#include "test/network/network_emulation_manager.h"
|
|
#include "test/network/simulated_network.h"
|
|
#include "test/wait_until.h"
|
|
|
|
namespace webrtc {
|
|
namespace test {
|
|
namespace {
|
|
|
|
using ::testing::Eq;
|
|
using ::testing::IsTrue;
|
|
|
|
constexpr int kMaxAptitude = 32000;
|
|
constexpr int kSamplingFrequency = 48000;
|
|
constexpr char kSignalThreadName[] = "signaling_thread";
|
|
|
|
bool AddIceCandidates(PeerConnectionWrapper* peer,
|
|
std::vector<const IceCandidateInterface*> candidates) {
|
|
bool success = true;
|
|
for (const auto candidate : candidates) {
|
|
if (!peer->pc()->AddIceCandidate(candidate)) {
|
|
success = false;
|
|
}
|
|
}
|
|
return success;
|
|
}
|
|
|
|
rtc::scoped_refptr<PeerConnectionFactoryInterface> CreatePeerConnectionFactory(
|
|
rtc::Thread* signaling_thread,
|
|
EmulatedNetworkManagerInterface* network) {
|
|
PeerConnectionFactoryDependencies pcf_deps;
|
|
pcf_deps.task_queue_factory = CreateDefaultTaskQueueFactory();
|
|
pcf_deps.event_log_factory = std::make_unique<RtcEventLogFactory>();
|
|
pcf_deps.network_thread = network->network_thread();
|
|
pcf_deps.signaling_thread = signaling_thread;
|
|
pcf_deps.trials = std::make_unique<FieldTrialBasedConfig>();
|
|
pcf_deps.socket_factory = network->socket_factory();
|
|
pcf_deps.network_manager = network->ReleaseNetworkManager();
|
|
|
|
pcf_deps.adm = TestAudioDeviceModule::Create(
|
|
pcf_deps.task_queue_factory.get(),
|
|
TestAudioDeviceModule::CreatePulsedNoiseCapturer(kMaxAptitude,
|
|
kSamplingFrequency),
|
|
TestAudioDeviceModule::CreateDiscardRenderer(kSamplingFrequency),
|
|
/*speed=*/1.f);
|
|
EnableMediaWithDefaults(pcf_deps);
|
|
return CreateModularPeerConnectionFactory(std::move(pcf_deps));
|
|
}
|
|
|
|
rtc::scoped_refptr<PeerConnectionInterface> CreatePeerConnection(
|
|
const rtc::scoped_refptr<PeerConnectionFactoryInterface>& pcf,
|
|
PeerConnectionObserver* observer,
|
|
EmulatedTURNServerInterface* turn_server = nullptr) {
|
|
PeerConnectionDependencies pc_deps(observer);
|
|
PeerConnectionInterface::RTCConfiguration rtc_configuration;
|
|
rtc_configuration.sdp_semantics = SdpSemantics::kUnifiedPlan;
|
|
// This test does not support TCP
|
|
rtc_configuration.port_allocator_config.flags =
|
|
cricket::PORTALLOCATOR_DISABLE_TCP;
|
|
if (turn_server != nullptr) {
|
|
webrtc::PeerConnectionInterface::IceServer server;
|
|
server.username = turn_server->GetIceServerConfig().username;
|
|
server.password = turn_server->GetIceServerConfig().username;
|
|
server.urls.push_back(turn_server->GetIceServerConfig().url);
|
|
rtc_configuration.servers.push_back(server);
|
|
}
|
|
|
|
auto result =
|
|
pcf->CreatePeerConnectionOrError(rtc_configuration, std::move(pc_deps));
|
|
if (!result.ok()) {
|
|
return nullptr;
|
|
}
|
|
return result.MoveValue();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST(NetworkEmulationManagerPCTest, Run) {
|
|
std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
|
|
signaling_thread->SetName(kSignalThreadName, nullptr);
|
|
signaling_thread->Start();
|
|
|
|
// Setup emulated network
|
|
NetworkEmulationManagerImpl emulation({.time_mode = TimeMode::kRealTime});
|
|
|
|
EmulatedNetworkNode* alice_node = emulation.CreateEmulatedNode(
|
|
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
|
|
EmulatedNetworkNode* bob_node = emulation.CreateEmulatedNode(
|
|
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
|
|
EmulatedEndpoint* alice_endpoint =
|
|
emulation.CreateEndpoint(EmulatedEndpointConfig());
|
|
EmulatedEndpoint* bob_endpoint =
|
|
emulation.CreateEndpoint(EmulatedEndpointConfig());
|
|
emulation.CreateRoute(alice_endpoint, {alice_node}, bob_endpoint);
|
|
emulation.CreateRoute(bob_endpoint, {bob_node}, alice_endpoint);
|
|
|
|
EmulatedNetworkManagerInterface* alice_network =
|
|
emulation.CreateEmulatedNetworkManagerInterface({alice_endpoint});
|
|
EmulatedNetworkManagerInterface* bob_network =
|
|
emulation.CreateEmulatedNetworkManagerInterface({bob_endpoint});
|
|
|
|
// Setup peer connections.
|
|
rtc::scoped_refptr<PeerConnectionFactoryInterface> alice_pcf;
|
|
rtc::scoped_refptr<PeerConnectionInterface> alice_pc;
|
|
std::unique_ptr<MockPeerConnectionObserver> alice_observer =
|
|
std::make_unique<MockPeerConnectionObserver>();
|
|
|
|
rtc::scoped_refptr<PeerConnectionFactoryInterface> bob_pcf;
|
|
rtc::scoped_refptr<PeerConnectionInterface> bob_pc;
|
|
std::unique_ptr<MockPeerConnectionObserver> bob_observer =
|
|
std::make_unique<MockPeerConnectionObserver>();
|
|
|
|
SendTask(signaling_thread.get(), [&]() {
|
|
alice_pcf =
|
|
CreatePeerConnectionFactory(signaling_thread.get(), alice_network);
|
|
alice_pc = CreatePeerConnection(alice_pcf, alice_observer.get());
|
|
|
|
bob_pcf = CreatePeerConnectionFactory(signaling_thread.get(), bob_network);
|
|
bob_pc = CreatePeerConnection(bob_pcf, bob_observer.get());
|
|
});
|
|
|
|
std::unique_ptr<PeerConnectionWrapper> alice =
|
|
std::make_unique<PeerConnectionWrapper>(alice_pcf, alice_pc,
|
|
std::move(alice_observer));
|
|
std::unique_ptr<PeerConnectionWrapper> bob =
|
|
std::make_unique<PeerConnectionWrapper>(bob_pcf, bob_pc,
|
|
std::move(bob_observer));
|
|
|
|
SendTask(signaling_thread.get(), [&]() {
|
|
rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
|
|
alice_pcf->CreateAudioSource(cricket::AudioOptions());
|
|
rtc::scoped_refptr<AudioTrackInterface> track =
|
|
alice_pcf->CreateAudioTrack("audio", source.get());
|
|
alice->AddTransceiver(track);
|
|
|
|
// Connect peers.
|
|
ASSERT_TRUE(alice->ExchangeOfferAnswerWith(bob.get()));
|
|
// Do the SDP negotiation, and also exchange ice candidates.
|
|
ASSERT_THAT(WaitUntil([&] { return alice->signaling_state(); },
|
|
Eq(PeerConnectionInterface::kStable)),
|
|
IsRtcOk());
|
|
ASSERT_THAT(
|
|
WaitUntil([&] { return alice->IsIceGatheringDone(); }, IsTrue()),
|
|
IsRtcOk());
|
|
ASSERT_THAT(WaitUntil([&] { return bob->IsIceGatheringDone(); }, IsTrue()),
|
|
IsRtcOk());
|
|
|
|
// Connect an ICE candidate pairs.
|
|
ASSERT_TRUE(
|
|
AddIceCandidates(bob.get(), alice->observer()->GetAllCandidates()));
|
|
ASSERT_TRUE(
|
|
AddIceCandidates(alice.get(), bob->observer()->GetAllCandidates()));
|
|
// This means that ICE and DTLS are connected.
|
|
ASSERT_THAT(WaitUntil([&] { return bob->IsIceConnected(); }, IsTrue()),
|
|
IsRtcOk());
|
|
ASSERT_THAT(WaitUntil([&] { return alice->IsIceConnected(); }, IsTrue()),
|
|
IsRtcOk());
|
|
|
|
// Close peer connections
|
|
alice->pc()->Close();
|
|
bob->pc()->Close();
|
|
|
|
// Delete peers.
|
|
alice.reset();
|
|
bob.reset();
|
|
});
|
|
}
|
|
|
|
TEST(NetworkEmulationManagerPCTest, RunTURN) {
|
|
std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
|
|
signaling_thread->SetName(kSignalThreadName, nullptr);
|
|
signaling_thread->Start();
|
|
|
|
// Setup emulated network
|
|
NetworkEmulationManagerImpl emulation({.time_mode = TimeMode::kRealTime});
|
|
|
|
EmulatedNetworkNode* alice_node = emulation.CreateEmulatedNode(
|
|
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
|
|
EmulatedNetworkNode* bob_node = emulation.CreateEmulatedNode(
|
|
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
|
|
EmulatedNetworkNode* turn_node = emulation.CreateEmulatedNode(
|
|
std::make_unique<SimulatedNetwork>(BuiltInNetworkBehaviorConfig()));
|
|
EmulatedEndpoint* alice_endpoint =
|
|
emulation.CreateEndpoint(EmulatedEndpointConfig());
|
|
EmulatedEndpoint* bob_endpoint =
|
|
emulation.CreateEndpoint(EmulatedEndpointConfig());
|
|
EmulatedTURNServerInterface* alice_turn =
|
|
emulation.CreateTURNServer(EmulatedTURNServerConfig());
|
|
EmulatedTURNServerInterface* bob_turn =
|
|
emulation.CreateTURNServer(EmulatedTURNServerConfig());
|
|
|
|
emulation.CreateRoute(alice_endpoint, {alice_node},
|
|
alice_turn->GetClientEndpoint());
|
|
emulation.CreateRoute(alice_turn->GetClientEndpoint(), {alice_node},
|
|
alice_endpoint);
|
|
|
|
emulation.CreateRoute(bob_endpoint, {bob_node},
|
|
bob_turn->GetClientEndpoint());
|
|
emulation.CreateRoute(bob_turn->GetClientEndpoint(), {bob_node},
|
|
bob_endpoint);
|
|
|
|
emulation.CreateRoute(alice_turn->GetPeerEndpoint(), {turn_node},
|
|
bob_turn->GetPeerEndpoint());
|
|
emulation.CreateRoute(bob_turn->GetPeerEndpoint(), {turn_node},
|
|
alice_turn->GetPeerEndpoint());
|
|
|
|
EmulatedNetworkManagerInterface* alice_network =
|
|
emulation.CreateEmulatedNetworkManagerInterface({alice_endpoint});
|
|
EmulatedNetworkManagerInterface* bob_network =
|
|
emulation.CreateEmulatedNetworkManagerInterface({bob_endpoint});
|
|
|
|
// Setup peer connections.
|
|
rtc::scoped_refptr<PeerConnectionFactoryInterface> alice_pcf;
|
|
rtc::scoped_refptr<PeerConnectionInterface> alice_pc;
|
|
std::unique_ptr<MockPeerConnectionObserver> alice_observer =
|
|
std::make_unique<MockPeerConnectionObserver>();
|
|
|
|
rtc::scoped_refptr<PeerConnectionFactoryInterface> bob_pcf;
|
|
rtc::scoped_refptr<PeerConnectionInterface> bob_pc;
|
|
std::unique_ptr<MockPeerConnectionObserver> bob_observer =
|
|
std::make_unique<MockPeerConnectionObserver>();
|
|
|
|
SendTask(signaling_thread.get(), [&]() {
|
|
alice_pcf =
|
|
CreatePeerConnectionFactory(signaling_thread.get(), alice_network);
|
|
alice_pc =
|
|
CreatePeerConnection(alice_pcf, alice_observer.get(), alice_turn);
|
|
|
|
bob_pcf = CreatePeerConnectionFactory(signaling_thread.get(), bob_network);
|
|
bob_pc = CreatePeerConnection(bob_pcf, bob_observer.get(), bob_turn);
|
|
});
|
|
|
|
std::unique_ptr<PeerConnectionWrapper> alice =
|
|
std::make_unique<PeerConnectionWrapper>(alice_pcf, alice_pc,
|
|
std::move(alice_observer));
|
|
std::unique_ptr<PeerConnectionWrapper> bob =
|
|
std::make_unique<PeerConnectionWrapper>(bob_pcf, bob_pc,
|
|
std::move(bob_observer));
|
|
|
|
SendTask(signaling_thread.get(), [&]() {
|
|
rtc::scoped_refptr<webrtc::AudioSourceInterface> source =
|
|
alice_pcf->CreateAudioSource(cricket::AudioOptions());
|
|
rtc::scoped_refptr<AudioTrackInterface> track =
|
|
alice_pcf->CreateAudioTrack("audio", source.get());
|
|
alice->AddTransceiver(track);
|
|
|
|
// Connect peers.
|
|
ASSERT_TRUE(alice->ExchangeOfferAnswerWith(bob.get()));
|
|
// Do the SDP negotiation, and also exchange ice candidates.
|
|
ASSERT_THAT(WaitUntil([&] { return alice->signaling_state(); },
|
|
Eq(PeerConnectionInterface::kStable)),
|
|
IsRtcOk());
|
|
ASSERT_THAT(
|
|
WaitUntil([&] { return alice->IsIceGatheringDone(); }, IsTrue()),
|
|
IsRtcOk());
|
|
ASSERT_THAT(WaitUntil([&] { return bob->IsIceGatheringDone(); }, IsTrue()),
|
|
IsRtcOk());
|
|
|
|
// Connect an ICE candidate pairs.
|
|
ASSERT_TRUE(
|
|
AddIceCandidates(bob.get(), alice->observer()->GetAllCandidates()));
|
|
ASSERT_TRUE(
|
|
AddIceCandidates(alice.get(), bob->observer()->GetAllCandidates()));
|
|
// This means that ICE and DTLS are connected.
|
|
ASSERT_THAT(WaitUntil([&] { return bob->IsIceConnected(); }, IsTrue()),
|
|
IsRtcOk());
|
|
ASSERT_THAT(WaitUntil([&] { return alice->IsIceConnected(); }, IsTrue()),
|
|
IsRtcOk());
|
|
|
|
// Close peer connections
|
|
alice->pc()->Close();
|
|
bob->pc()->Close();
|
|
|
|
// Delete peers.
|
|
alice.reset();
|
|
bob.reset();
|
|
});
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace webrtc
|