/* * Copyright 2020 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 "pc/connection_context.h" #include #include #include #include "api/environment/environment.h" #include "media/base/media_engine.h" #include "media/sctp/sctp_transport_factory.h" #include "pc/media_factory.h" #include "rtc_base/helpers.h" #include "rtc_base/internal/default_socket_server.h" #include "rtc_base/socket_server.h" #include "rtc_base/time_utils.h" namespace webrtc { namespace { rtc::Thread* MaybeStartNetworkThread( rtc::Thread* old_thread, std::unique_ptr& socket_factory_holder, std::unique_ptr& thread_holder) { if (old_thread) { return old_thread; } std::unique_ptr socket_server = rtc::CreateDefaultSocketServer(); thread_holder = std::make_unique(socket_server.get()); socket_factory_holder = std::move(socket_server); thread_holder->SetName("pc_network_thread", nullptr); thread_holder->Start(); return thread_holder.get(); } rtc::Thread* MaybeWrapThread(rtc::Thread* signaling_thread, bool& wraps_current_thread) { wraps_current_thread = false; if (signaling_thread) { return signaling_thread; } auto this_thread = rtc::Thread::Current(); if (!this_thread) { // If this thread isn't already wrapped by an rtc::Thread, create a // wrapper and own it in this class. this_thread = rtc::ThreadManager::Instance()->WrapCurrentThread(); wraps_current_thread = true; } return this_thread; } std::unique_ptr MaybeCreateSctpFactory( std::unique_ptr factory, rtc::Thread* network_thread) { if (factory) { return factory; } #ifdef WEBRTC_HAVE_SCTP return std::make_unique(network_thread); #else return nullptr; #endif } } // namespace // Static rtc::scoped_refptr ConnectionContext::Create( const Environment& env, PeerConnectionFactoryDependencies* dependencies) { return rtc::scoped_refptr( new ConnectionContext(env, dependencies)); } ConnectionContext::ConnectionContext( const Environment& env, PeerConnectionFactoryDependencies* dependencies) : network_thread_(MaybeStartNetworkThread(dependencies->network_thread, owned_socket_factory_, owned_network_thread_)), worker_thread_(dependencies->worker_thread, []() { auto thread_holder = rtc::Thread::Create(); thread_holder->SetName("pc_worker_thread", nullptr); thread_holder->Start(); return thread_holder; }), signaling_thread_(MaybeWrapThread(dependencies->signaling_thread, wraps_current_thread_)), env_(env), media_engine_( dependencies->media_factory != nullptr ? dependencies->media_factory->CreateMediaEngine(env_, *dependencies) : nullptr), network_monitor_factory_( std::move(dependencies->network_monitor_factory)), default_network_manager_(std::move(dependencies->network_manager)), call_factory_(std::move(dependencies->media_factory)), default_socket_factory_(std::move(dependencies->packet_socket_factory)), sctp_factory_( MaybeCreateSctpFactory(std::move(dependencies->sctp_factory), network_thread())), use_rtx_(true) { RTC_DCHECK_RUN_ON(signaling_thread_); RTC_DCHECK(!(default_network_manager_ && network_monitor_factory_)) << "You can't set both network_manager and network_monitor_factory."; signaling_thread_->AllowInvokesToThread(worker_thread()); signaling_thread_->AllowInvokesToThread(network_thread_); worker_thread_->AllowInvokesToThread(network_thread_); if (!network_thread_->IsCurrent()) { // network_thread_->IsCurrent() == true means signaling_thread_ is // network_thread_. In this case, no further action is required as // signaling_thread_ can already invoke network_thread_. network_thread_->PostTask( [thread = network_thread_, worker_thread = worker_thread_.get()] { thread->DisallowBlockingCalls(); thread->DisallowAllInvokes(); if (worker_thread == thread) { // In this case, worker_thread_ == network_thread_ thread->AllowInvokesToThread(thread); } }); } rtc::InitRandom(rtc::Time32()); rtc::SocketFactory* socket_factory = dependencies->socket_factory; if (socket_factory == nullptr) { if (owned_socket_factory_) { socket_factory = owned_socket_factory_.get(); } else { // TODO(bugs.webrtc.org/13145): This case should be deleted. Either // require that a PacketSocketFactory and NetworkManager always are // injected (with no need to construct these default objects), or require // that if a network_thread is injected, an approprite rtc::SocketServer // should be injected too. socket_factory = network_thread()->socketserver(); } } if (!default_network_manager_) { // If network_monitor_factory_ is non-null, it will be used to create a // network monitor while on the network thread. default_network_manager_ = std::make_unique( network_monitor_factory_.get(), socket_factory, &env_.field_trials()); } if (!default_socket_factory_) { default_socket_factory_ = std::make_unique(socket_factory); } // Set warning levels on the threads, to give warnings when response // may be slower than is expected of the thread. // Since some of the threads may be the same, start with the least // restrictive limits and end with the least permissive ones. // This will give warnings for all cases. signaling_thread_->SetDispatchWarningMs(100); worker_thread_->SetDispatchWarningMs(30); network_thread_->SetDispatchWarningMs(10); if (media_engine_) { // TODO(tommi): Change VoiceEngine to do ctor time initialization so that // this isn't necessary. worker_thread_->BlockingCall([&] { media_engine_->Init(); }); } } ConnectionContext::~ConnectionContext() { RTC_DCHECK_RUN_ON(signaling_thread_); // `media_engine_` requires destruction to happen on the worker thread. worker_thread_->PostTask([media_engine = std::move(media_engine_)] {}); // Make sure `worker_thread()` and `signaling_thread()` outlive // `default_socket_factory_` and `default_network_manager_`. default_socket_factory_ = nullptr; default_network_manager_ = nullptr; if (wraps_current_thread_) rtc::ThreadManager::Instance()->UnwrapCurrentThread(); } } // namespace webrtc