/* * Copyright 2004 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/peer_connection_factory.h" #include #include #include "absl/strings/match.h" #include "api/environment/environment.h" #include "api/environment/environment_factory.h" #include "api/fec_controller.h" #include "api/ice_transport_interface.h" #include "api/network_state_predictor.h" #include "api/packet_socket_factory.h" #include "api/rtc_event_log/rtc_event_log.h" #include "api/sequence_checker.h" #include "api/transport/bitrate_settings.h" #include "api/units/data_rate.h" #include "call/audio_state.h" #include "call/rtp_transport_controller_send_factory.h" #include "media/base/media_engine.h" #include "p2p/base/basic_packet_socket_factory.h" #include "p2p/base/default_ice_transport_factory.h" #include "p2p/base/port_allocator.h" #include "p2p/client/basic_port_allocator.h" #include "pc/audio_track.h" #include "pc/local_audio_source.h" #include "pc/media_factory.h" #include "pc/media_stream.h" #include "pc/media_stream_proxy.h" #include "pc/media_stream_track_proxy.h" #include "pc/peer_connection.h" #include "pc/peer_connection_factory_proxy.h" #include "pc/peer_connection_proxy.h" #include "pc/rtp_parameters_conversion.h" #include "pc/session_description.h" #include "pc/video_track.h" #include "rtc_base/checks.h" #include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/experiments/field_trial_units.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/rtc_certificate_generator.h" #include "rtc_base/system/file_wrapper.h" namespace webrtc { rtc::scoped_refptr CreateModularPeerConnectionFactory( PeerConnectionFactoryDependencies dependencies) { // The PeerConnectionFactory must be created on the signaling thread. if (dependencies.signaling_thread && !dependencies.signaling_thread->IsCurrent()) { return dependencies.signaling_thread->BlockingCall([&dependencies] { return CreateModularPeerConnectionFactory(std::move(dependencies)); }); } auto pc_factory = PeerConnectionFactory::Create(std::move(dependencies)); if (!pc_factory) { return nullptr; } // Verify that the invocation and the initialization ended up agreeing on the // thread. RTC_DCHECK_RUN_ON(pc_factory->signaling_thread()); return PeerConnectionFactoryProxy::Create( pc_factory->signaling_thread(), pc_factory->worker_thread(), pc_factory); } // Static rtc::scoped_refptr PeerConnectionFactory::Create( PeerConnectionFactoryDependencies dependencies) { auto context = ConnectionContext::Create( CreateEnvironment(std::move(dependencies.trials), std::move(dependencies.task_queue_factory)), &dependencies); if (!context) { return nullptr; } return rtc::make_ref_counted(context, &dependencies); } PeerConnectionFactory::PeerConnectionFactory( rtc::scoped_refptr context, PeerConnectionFactoryDependencies* dependencies) : context_(context), event_log_factory_(std::move(dependencies->event_log_factory)), fec_controller_factory_(std::move(dependencies->fec_controller_factory)), network_state_predictor_factory_( std::move(dependencies->network_state_predictor_factory)), injected_network_controller_factory_( std::move(dependencies->network_controller_factory)), neteq_factory_(std::move(dependencies->neteq_factory)), transport_controller_send_factory_( (dependencies->transport_controller_send_factory) ? std::move(dependencies->transport_controller_send_factory) : std::make_unique()), decode_metronome_(std::move(dependencies->decode_metronome)), encode_metronome_(std::move(dependencies->encode_metronome)) {} PeerConnectionFactory::PeerConnectionFactory( PeerConnectionFactoryDependencies dependencies) : PeerConnectionFactory( ConnectionContext::Create( CreateEnvironment(std::move(dependencies.trials), std::move(dependencies.task_queue_factory)), &dependencies), &dependencies) {} PeerConnectionFactory::~PeerConnectionFactory() { RTC_DCHECK_RUN_ON(signaling_thread()); worker_thread()->BlockingCall([this] { RTC_DCHECK_RUN_ON(worker_thread()); decode_metronome_ = nullptr; encode_metronome_ = nullptr; }); } void PeerConnectionFactory::SetOptions(const Options& options) { RTC_DCHECK_RUN_ON(signaling_thread()); options_ = options; } RtpCapabilities PeerConnectionFactory::GetRtpSenderCapabilities( cricket::MediaType kind) const { RTC_DCHECK_RUN_ON(signaling_thread()); switch (kind) { case cricket::MEDIA_TYPE_AUDIO: { cricket::AudioCodecs cricket_codecs; cricket_codecs = media_engine()->voice().send_codecs(); auto extensions = GetDefaultEnabledRtpHeaderExtensions(media_engine()->voice()); return ToRtpCapabilities(cricket_codecs, extensions); } case cricket::MEDIA_TYPE_VIDEO: { cricket::VideoCodecs cricket_codecs; cricket_codecs = media_engine()->video().send_codecs(context_->use_rtx()); auto extensions = GetDefaultEnabledRtpHeaderExtensions(media_engine()->video()); return ToRtpCapabilities(cricket_codecs, extensions); } case cricket::MEDIA_TYPE_DATA: return RtpCapabilities(); case cricket::MEDIA_TYPE_UNSUPPORTED: return RtpCapabilities(); } RTC_DLOG(LS_ERROR) << "Got unexpected MediaType " << kind; RTC_CHECK_NOTREACHED(); } RtpCapabilities PeerConnectionFactory::GetRtpReceiverCapabilities( cricket::MediaType kind) const { RTC_DCHECK_RUN_ON(signaling_thread()); switch (kind) { case cricket::MEDIA_TYPE_AUDIO: { cricket::AudioCodecs cricket_codecs; cricket_codecs = media_engine()->voice().recv_codecs(); auto extensions = GetDefaultEnabledRtpHeaderExtensions(media_engine()->voice()); return ToRtpCapabilities(cricket_codecs, extensions); } case cricket::MEDIA_TYPE_VIDEO: { cricket::VideoCodecs cricket_codecs = media_engine()->video().recv_codecs(context_->use_rtx()); auto extensions = GetDefaultEnabledRtpHeaderExtensions(media_engine()->video()); return ToRtpCapabilities(cricket_codecs, extensions); } case cricket::MEDIA_TYPE_DATA: return RtpCapabilities(); case cricket::MEDIA_TYPE_UNSUPPORTED: return RtpCapabilities(); } RTC_DLOG(LS_ERROR) << "Got unexpected MediaType " << kind; RTC_CHECK_NOTREACHED(); } rtc::scoped_refptr PeerConnectionFactory::CreateAudioSource(const cricket::AudioOptions& options) { RTC_DCHECK(signaling_thread()->IsCurrent()); rtc::scoped_refptr source( LocalAudioSource::Create(&options)); return source; } bool PeerConnectionFactory::StartAecDump(FILE* file, int64_t max_size_bytes) { RTC_DCHECK_RUN_ON(worker_thread()); return media_engine()->voice().StartAecDump(FileWrapper(file), max_size_bytes); } void PeerConnectionFactory::StopAecDump() { RTC_DCHECK_RUN_ON(worker_thread()); media_engine()->voice().StopAecDump(); } cricket::MediaEngineInterface* PeerConnectionFactory::media_engine() const { RTC_DCHECK(context_); return context_->media_engine(); } RTCErrorOr> PeerConnectionFactory::CreatePeerConnectionOrError( const PeerConnectionInterface::RTCConfiguration& configuration, PeerConnectionDependencies dependencies) { RTC_DCHECK_RUN_ON(signaling_thread()); EnvironmentFactory env_factory(context_->env()); // Field trials active for this PeerConnection is the first of: // a) Specified in the PeerConnectionDependencies // b) Specified in the PeerConnectionFactoryDependencies // c) Created as default by the EnvironmentFactory. env_factory.Set(std::move(dependencies.trials)); if (event_log_factory_ != nullptr) { worker_thread()->BlockingCall([&] { Environment env_for_rtc_event_log = env_factory.Create(); env_factory.Set(event_log_factory_->Create(env_for_rtc_event_log)); }); } const Environment env = env_factory.Create(); // Set internal defaults if optional dependencies are not set. if (!dependencies.cert_generator) { dependencies.cert_generator = std::make_unique(signaling_thread(), network_thread()); } if (!dependencies.allocator) { dependencies.allocator = std::make_unique( context_->default_network_manager(), context_->default_socket_factory(), configuration.turn_customizer, /*relay_port_factory=*/nullptr, &env.field_trials()); dependencies.allocator->SetPortRange( configuration.port_allocator_config.min_port, configuration.port_allocator_config.max_port); dependencies.allocator->set_flags( configuration.port_allocator_config.flags); } if (!dependencies.ice_transport_factory) { dependencies.ice_transport_factory = std::make_unique(); } dependencies.allocator->SetNetworkIgnoreMask(options().network_ignore_mask); dependencies.allocator->SetVpnList(configuration.vpn_list); std::unique_ptr call = worker_thread()->BlockingCall([this, &env, &configuration] { return CreateCall_w(env, configuration); }); auto result = PeerConnection::Create(env, context_, options_, std::move(call), configuration, std::move(dependencies)); if (!result.ok()) { return result.MoveError(); } // We configure the proxy with a pointer to the network thread for methods // that need to be invoked there rather than on the signaling thread. // Internally, the proxy object has a member variable named `worker_thread_` // which will point to the network thread (and not the factory's // worker_thread()). All such methods have thread checks though, so the code // should still be clear (outside of macro expansion). rtc::scoped_refptr result_proxy = PeerConnectionProxy::Create(signaling_thread(), network_thread(), result.MoveValue()); return result_proxy; } rtc::scoped_refptr PeerConnectionFactory::CreateLocalMediaStream(const std::string& stream_id) { RTC_DCHECK(signaling_thread()->IsCurrent()); return MediaStreamProxy::Create(signaling_thread(), MediaStream::Create(stream_id)); } rtc::scoped_refptr PeerConnectionFactory::CreateVideoTrack( rtc::scoped_refptr source, absl::string_view id) { RTC_DCHECK(signaling_thread()->IsCurrent()); rtc::scoped_refptr track = VideoTrack::Create(id, source, worker_thread()); return VideoTrackProxy::Create(signaling_thread(), worker_thread(), track); } rtc::scoped_refptr PeerConnectionFactory::CreateAudioTrack( const std::string& id, AudioSourceInterface* source) { RTC_DCHECK(signaling_thread()->IsCurrent()); rtc::scoped_refptr track = AudioTrack::Create(id, rtc::scoped_refptr(source)); return AudioTrackProxy::Create(signaling_thread(), track); } std::unique_ptr PeerConnectionFactory::CreateCall_w( const Environment& env, const PeerConnectionInterface::RTCConfiguration& configuration) { RTC_DCHECK_RUN_ON(worker_thread()); CallConfig call_config(env, network_thread()); if (!media_engine() || !context_->call_factory()) { return nullptr; } call_config.audio_state = media_engine()->voice().GetAudioState(); FieldTrialParameter min_bandwidth("min", DataRate::KilobitsPerSec(30)); FieldTrialParameter start_bandwidth("start", DataRate::KilobitsPerSec(300)); FieldTrialParameter max_bandwidth("max", DataRate::KilobitsPerSec(2000)); ParseFieldTrial({&min_bandwidth, &start_bandwidth, &max_bandwidth}, env.field_trials().Lookup("WebRTC-PcFactoryDefaultBitrates")); call_config.bitrate_config.min_bitrate_bps = rtc::saturated_cast(min_bandwidth->bps()); call_config.bitrate_config.start_bitrate_bps = rtc::saturated_cast(start_bandwidth->bps()); call_config.bitrate_config.max_bitrate_bps = rtc::saturated_cast(max_bandwidth->bps()); call_config.fec_controller_factory = fec_controller_factory_.get(); call_config.network_state_predictor_factory = network_state_predictor_factory_.get(); call_config.neteq_factory = neteq_factory_.get(); if (IsTrialEnabled("WebRTC-Bwe-InjectedCongestionController")) { RTC_LOG(LS_INFO) << "Using injected network controller factory"; call_config.network_controller_factory = injected_network_controller_factory_.get(); } else { RTC_LOG(LS_INFO) << "Using default network controller factory"; } call_config.rtp_transport_controller_send_factory = transport_controller_send_factory_.get(); call_config.decode_metronome = decode_metronome_.get(); call_config.encode_metronome = encode_metronome_.get(); call_config.pacer_burst_interval = configuration.pacer_burst_interval; return context_->call_factory()->CreateCall(call_config); } bool PeerConnectionFactory::IsTrialEnabled(absl::string_view key) const { return absl::StartsWith(field_trials().Lookup(key), "Enabled"); } } // namespace webrtc