/* * Copyright 2017 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 "ortc/ortcfactory.h" #include #include // For std::move. #include #include "absl/memory/memory.h" #include "api/mediastreamtrackproxy.h" #include "api/proxy.h" #include "api/rtcerror.h" #include "api/video_codecs/builtin_video_decoder_factory.h" #include "api/video_codecs/builtin_video_encoder_factory.h" #include "api/videosourceproxy.h" #include "logging/rtc_event_log/rtc_event_log.h" #include "media/base/mediaconstants.h" #include "media/base/rtpdataengine.h" #include "modules/audio_processing/include/audio_processing.h" #include "ortc/ortcrtpreceiveradapter.h" #include "ortc/ortcrtpsenderadapter.h" #include "ortc/rtptransportadapter.h" #include "ortc/rtptransportcontrolleradapter.h" #include "p2p/base/basicpacketsocketfactory.h" #include "p2p/base/udptransport.h" #include "pc/audiotrack.h" #include "pc/channelmanager.h" #include "pc/localaudiosource.h" #include "pc/rtpparametersconversion.h" #include "pc/videotrack.h" #include "rtc_base/asyncpacketsocket.h" #include "rtc_base/bind.h" #include "rtc_base/checks.h" #include "rtc_base/helpers.h" #include "rtc_base/logging.h" namespace { const int kDefaultRtcpCnameLength = 16; // Asserts that all of the built-in capabilities can be converted to // RtpCapabilities. If they can't, something's wrong (for example, maybe a new // feedback mechanism is supported, but an enum value wasn't added to // rtpparameters.h). template webrtc::RtpCapabilities ToRtpCapabilitiesWithAsserts( const std::vector& cricket_codecs, const cricket::RtpHeaderExtensions& cricket_extensions) { webrtc::RtpCapabilities capabilities = webrtc::ToRtpCapabilities(cricket_codecs, cricket_extensions); RTC_DCHECK_EQ(capabilities.codecs.size(), cricket_codecs.size()); for (size_t i = 0; i < capabilities.codecs.size(); ++i) { RTC_DCHECK_EQ(capabilities.codecs[i].rtcp_feedback.size(), cricket_codecs[i].feedback_params.params().size()); } RTC_DCHECK_EQ(capabilities.header_extensions.size(), cricket_extensions.size()); return capabilities; } } // namespace namespace webrtc { // Note that this proxy class uses the network thread as the "worker" thread. BEGIN_OWNED_PROXY_MAP(OrtcFactory) PROXY_SIGNALING_THREAD_DESTRUCTOR() PROXY_METHOD0(RTCErrorOr>, CreateRtpTransportController) PROXY_METHOD4(RTCErrorOr>, CreateRtpTransport, const RtpTransportParameters&, PacketTransportInterface*, PacketTransportInterface*, RtpTransportControllerInterface*) PROXY_METHOD4(RTCErrorOr>, CreateSrtpTransport, const RtpTransportParameters&, PacketTransportInterface*, PacketTransportInterface*, RtpTransportControllerInterface*) PROXY_CONSTMETHOD1(RtpCapabilities, GetRtpSenderCapabilities, cricket::MediaType) PROXY_METHOD2(RTCErrorOr>, CreateRtpSender, rtc::scoped_refptr, RtpTransportInterface*) PROXY_METHOD2(RTCErrorOr>, CreateRtpSender, cricket::MediaType, RtpTransportInterface*) PROXY_CONSTMETHOD1(RtpCapabilities, GetRtpReceiverCapabilities, cricket::MediaType) PROXY_METHOD2(RTCErrorOr>, CreateRtpReceiver, cricket::MediaType, RtpTransportInterface*) PROXY_WORKER_METHOD3(RTCErrorOr>, CreateUdpTransport, int, uint16_t, uint16_t) PROXY_METHOD1(rtc::scoped_refptr, CreateAudioSource, const cricket::AudioOptions&) PROXY_METHOD2(rtc::scoped_refptr, CreateVideoTrack, const std::string&, VideoTrackSourceInterface*) PROXY_METHOD2(rtc::scoped_refptr, CreateAudioTrack, const std::string&, AudioSourceInterface*) END_PROXY_MAP() // static RTCErrorOr> OrtcFactory::Create( rtc::Thread* network_thread, rtc::Thread* signaling_thread, rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, AudioDeviceModule* adm, std::unique_ptr media_engine, rtc::scoped_refptr audio_encoder_factory, rtc::scoped_refptr audio_decoder_factory) { // Hop to signaling thread if needed. if (signaling_thread && !signaling_thread->IsCurrent()) { return signaling_thread ->Invoke>>( RTC_FROM_HERE, rtc::Bind(&OrtcFactory::Create_s, network_thread, signaling_thread, network_manager, socket_factory, adm, media_engine.release(), audio_encoder_factory, audio_decoder_factory)); } return Create_s(network_thread, signaling_thread, network_manager, socket_factory, adm, media_engine.release(), audio_encoder_factory, audio_decoder_factory); } RTCErrorOr> OrtcFactoryInterface::Create( rtc::Thread* network_thread, rtc::Thread* signaling_thread, rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, AudioDeviceModule* adm, rtc::scoped_refptr audio_encoder_factory, rtc::scoped_refptr audio_decoder_factory) { return OrtcFactory::Create(network_thread, signaling_thread, network_manager, socket_factory, adm, nullptr, audio_encoder_factory, audio_decoder_factory); } OrtcFactory::OrtcFactory( rtc::Thread* network_thread, rtc::Thread* signaling_thread, rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, AudioDeviceModule* adm, rtc::scoped_refptr audio_encoder_factory, rtc::scoped_refptr audio_decoder_factory) : network_thread_(network_thread), signaling_thread_(signaling_thread), network_manager_(network_manager), socket_factory_(socket_factory), adm_(adm), null_event_log_(RtcEventLog::CreateNull()), audio_encoder_factory_(audio_encoder_factory), audio_decoder_factory_(audio_decoder_factory) { if (!rtc::CreateRandomString(kDefaultRtcpCnameLength, &default_cname_)) { RTC_LOG(LS_ERROR) << "Failed to generate CNAME?"; RTC_NOTREACHED(); } if (!network_thread_) { owned_network_thread_ = rtc::Thread::CreateWithSocketServer(); owned_network_thread_->Start(); network_thread_ = owned_network_thread_.get(); } // The worker thread is created internally because it's an implementation // detail, and consumers of the API don't need to really know about it. worker_thread_ = rtc::Thread::Create(); worker_thread_->SetName("ORTC-worker", this); worker_thread_->Start(); if (signaling_thread_) { RTC_DCHECK_RUN_ON(signaling_thread_); } else { signaling_thread_ = rtc::Thread::Current(); if (!signaling_thread_) { // If this thread isn't already wrapped by an rtc::Thread, create a // wrapper and own it in this class. signaling_thread_ = rtc::ThreadManager::Instance()->WrapCurrentThread(); wraps_signaling_thread_ = true; } } if (signaling_thread_->name().empty()) { signaling_thread_->SetName("ORTC-signaling", this); } if (!network_manager_) { owned_network_manager_.reset(new rtc::BasicNetworkManager()); network_manager_ = owned_network_manager_.get(); } if (!socket_factory_) { owned_socket_factory_.reset( new rtc::BasicPacketSocketFactory(network_thread_)); socket_factory_ = owned_socket_factory_.get(); } } OrtcFactory::~OrtcFactory() { RTC_DCHECK_RUN_ON(signaling_thread_); if (wraps_signaling_thread_) { rtc::ThreadManager::Instance()->UnwrapCurrentThread(); } } RTCErrorOr> OrtcFactory::CreateRtpTransportController() { RTC_DCHECK_RUN_ON(signaling_thread_); return RtpTransportControllerAdapter::CreateProxied( cricket::MediaConfig(), channel_manager_.get(), null_event_log_.get(), signaling_thread_, worker_thread_.get(), network_thread_); } RTCErrorOr> OrtcFactory::CreateRtpTransport( const RtpTransportParameters& parameters, PacketTransportInterface* rtp, PacketTransportInterface* rtcp, RtpTransportControllerInterface* transport_controller) { RTC_DCHECK_RUN_ON(signaling_thread_); RtpTransportParameters copied_parameters = parameters; if (copied_parameters.rtcp.cname.empty()) { copied_parameters.rtcp.cname = default_cname_; } if (transport_controller) { return transport_controller->GetInternal()->CreateProxiedRtpTransport( copied_parameters, rtp, rtcp); } else { // If |transport_controller| is null, create one automatically, which the // returned RtpTransport will own. auto controller_result = CreateRtpTransportController(); if (!controller_result.ok()) { return controller_result.MoveError(); } auto controller = controller_result.MoveValue(); auto transport_result = controller->GetInternal()->CreateProxiedRtpTransport(copied_parameters, rtp, rtcp); // If RtpTransport was successfully created, transfer ownership of // |rtp_transport_controller|. Otherwise it will go out of scope and be // deleted automatically. if (transport_result.ok()) { transport_result.value() ->GetInternal() ->TakeOwnershipOfRtpTransportController(std::move(controller)); } return transport_result; } } RTCErrorOr> OrtcFactory::CreateSrtpTransport( const RtpTransportParameters& parameters, PacketTransportInterface* rtp, PacketTransportInterface* rtcp, RtpTransportControllerInterface* transport_controller) { RTC_DCHECK_RUN_ON(signaling_thread_); RtpTransportParameters copied_parameters = parameters; if (copied_parameters.rtcp.cname.empty()) { copied_parameters.rtcp.cname = default_cname_; } if (transport_controller) { return transport_controller->GetInternal()->CreateProxiedSrtpTransport( copied_parameters, rtp, rtcp); } else { // If |transport_controller| is null, create one automatically, which the // returned SrtpTransport will own. auto controller_result = CreateRtpTransportController(); if (!controller_result.ok()) { return controller_result.MoveError(); } auto controller = controller_result.MoveValue(); auto transport_result = controller->GetInternal()->CreateProxiedSrtpTransport(copied_parameters, rtp, rtcp); // If SrtpTransport was successfully created, transfer ownership of // |rtp_transport_controller|. Otherwise it will go out of scope and be // deleted automatically. if (transport_result.ok()) { transport_result.value() ->GetInternal() ->TakeOwnershipOfRtpTransportController(std::move(controller)); } return transport_result; } } RtpCapabilities OrtcFactory::GetRtpSenderCapabilities( cricket::MediaType kind) const { RTC_DCHECK_RUN_ON(signaling_thread_); switch (kind) { case cricket::MEDIA_TYPE_AUDIO: { cricket::AudioCodecs cricket_codecs; cricket::RtpHeaderExtensions cricket_extensions; channel_manager_->GetSupportedAudioSendCodecs(&cricket_codecs); channel_manager_->GetSupportedAudioRtpHeaderExtensions( &cricket_extensions); return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions); } case cricket::MEDIA_TYPE_VIDEO: { cricket::VideoCodecs cricket_codecs; cricket::RtpHeaderExtensions cricket_extensions; channel_manager_->GetSupportedVideoCodecs(&cricket_codecs); channel_manager_->GetSupportedVideoRtpHeaderExtensions( &cricket_extensions); return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions); } case cricket::MEDIA_TYPE_DATA: return RtpCapabilities(); } // Not reached; avoids compile warning. FATAL(); } RTCErrorOr> OrtcFactory::CreateRtpSender( rtc::scoped_refptr track, RtpTransportInterface* transport) { RTC_DCHECK_RUN_ON(signaling_thread_); if (!track) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Cannot pass null track into CreateRtpSender."); } auto result = CreateRtpSender(cricket::MediaTypeFromString(track->kind()), transport); if (!result.ok()) { return result; } auto err = result.value()->SetTrack(track); if (!err.ok()) { return std::move(err); } return result; } RTCErrorOr> OrtcFactory::CreateRtpSender(cricket::MediaType kind, RtpTransportInterface* transport) { RTC_DCHECK_RUN_ON(signaling_thread_); if (kind == cricket::MEDIA_TYPE_DATA) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Cannot create data RtpSender."); } if (!transport) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Cannot pass null transport into CreateRtpSender."); } return transport->GetInternal() ->rtp_transport_controller() ->CreateProxiedRtpSender(kind, transport); } RtpCapabilities OrtcFactory::GetRtpReceiverCapabilities( cricket::MediaType kind) const { RTC_DCHECK_RUN_ON(signaling_thread_); switch (kind) { case cricket::MEDIA_TYPE_AUDIO: { cricket::AudioCodecs cricket_codecs; cricket::RtpHeaderExtensions cricket_extensions; channel_manager_->GetSupportedAudioReceiveCodecs(&cricket_codecs); channel_manager_->GetSupportedAudioRtpHeaderExtensions( &cricket_extensions); return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions); } case cricket::MEDIA_TYPE_VIDEO: { cricket::VideoCodecs cricket_codecs; cricket::RtpHeaderExtensions cricket_extensions; channel_manager_->GetSupportedVideoCodecs(&cricket_codecs); channel_manager_->GetSupportedVideoRtpHeaderExtensions( &cricket_extensions); return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions); } case cricket::MEDIA_TYPE_DATA: return RtpCapabilities(); } // Not reached; avoids compile warning. FATAL(); } RTCErrorOr> OrtcFactory::CreateRtpReceiver(cricket::MediaType kind, RtpTransportInterface* transport) { RTC_DCHECK_RUN_ON(signaling_thread_); if (kind == cricket::MEDIA_TYPE_DATA) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Cannot create data RtpReceiver."); } if (!transport) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Cannot pass null transport into CreateRtpReceiver."); } return transport->GetInternal() ->rtp_transport_controller() ->CreateProxiedRtpReceiver(kind, transport); } // UdpTransport expects all methods to be called on one thread, which needs to // be the network thread, since that's where its socket can safely be used. So // return a proxy to the created UdpTransport. BEGIN_OWNED_PROXY_MAP(UdpTransport) PROXY_WORKER_THREAD_DESTRUCTOR() PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetLocalAddress) PROXY_WORKER_METHOD1(bool, SetRemoteAddress, const rtc::SocketAddress&) PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetRemoteAddress) protected: rtc::PacketTransportInternal* GetInternal() override { return internal(); } END_PROXY_MAP() RTCErrorOr> OrtcFactory::CreateUdpTransport(int family, uint16_t min_port, uint16_t max_port) { RTC_DCHECK_RUN_ON(network_thread_); if (family != AF_INET && family != AF_INET6) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER, "Address family must be AF_INET or AF_INET6."); } if (min_port > max_port) { LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE, "Port range invalid; minimum port must be less than " "or equal to max port."); } std::unique_ptr socket( socket_factory_->CreateUdpSocket( rtc::SocketAddress(rtc::GetAnyIP(family), 0), min_port, max_port)); if (!socket) { // Only log at warning level, because this method may be called with // specific port ranges to determine if a port is available, expecting the // possibility of an error. LOG_AND_RETURN_ERROR_EX(RTCErrorType::RESOURCE_EXHAUSTED, "Local socket allocation failure.", LS_WARNING); } RTC_LOG(LS_INFO) << "Created UDP socket with address " << socket->GetLocalAddress().ToSensitiveString() << "."; // Make a unique debug name (for logging/diagnostics only). std::ostringstream oss; static int udp_id = 0; oss << "udp" << udp_id++; return UdpTransportProxyWithInternal::Create( signaling_thread_, network_thread_, std::unique_ptr( new cricket::UdpTransport(oss.str(), std::move(socket)))); } rtc::scoped_refptr OrtcFactory::CreateAudioSource( const cricket::AudioOptions& options) { RTC_DCHECK_RUN_ON(signaling_thread_); return rtc::scoped_refptr( LocalAudioSource::Create(&options)); } rtc::scoped_refptr OrtcFactory::CreateVideoTrack( const std::string& id, VideoTrackSourceInterface* source) { RTC_DCHECK_RUN_ON(signaling_thread_); rtc::scoped_refptr track( VideoTrack::Create(id, source, worker_thread_.get())); return VideoTrackProxy::Create(signaling_thread_, worker_thread_.get(), track); } rtc::scoped_refptr OrtcFactory::CreateAudioTrack( const std::string& id, AudioSourceInterface* source) { RTC_DCHECK_RUN_ON(signaling_thread_); rtc::scoped_refptr track(AudioTrack::Create(id, source)); return AudioTrackProxy::Create(signaling_thread_, track); } // static RTCErrorOr> OrtcFactory::Create_s( rtc::Thread* network_thread, rtc::Thread* signaling_thread, rtc::NetworkManager* network_manager, rtc::PacketSocketFactory* socket_factory, AudioDeviceModule* adm, cricket::MediaEngineInterface* media_engine, rtc::scoped_refptr audio_encoder_factory, rtc::scoped_refptr audio_decoder_factory) { // Add the unique_ptr wrapper back. std::unique_ptr owned_media_engine( media_engine); std::unique_ptr new_factory(new OrtcFactory( network_thread, signaling_thread, network_manager, socket_factory, adm, audio_encoder_factory, audio_decoder_factory)); RTCError err = new_factory->Initialize(std::move(owned_media_engine)); if (!err.ok()) { return std::move(err); } // Return a proxy so that any calls on the returned object (including // destructor) happen on the signaling thread. rtc::Thread* signaling = new_factory->signaling_thread(); rtc::Thread* network = new_factory->network_thread(); return OrtcFactoryProxy::Create(signaling, network, std::move(new_factory)); } RTCError OrtcFactory::Initialize( std::unique_ptr media_engine) { RTC_DCHECK_RUN_ON(signaling_thread_); // TODO(deadbeef): Get rid of requirement to hop to worker thread here. if (!media_engine) { media_engine = worker_thread_->Invoke>( RTC_FROM_HERE, rtc::Bind(&OrtcFactory::CreateMediaEngine_w, this)); } channel_manager_.reset(new cricket::ChannelManager( std::move(media_engine), absl::make_unique(), worker_thread_.get(), network_thread_)); channel_manager_->SetVideoRtxEnabled(true); if (!channel_manager_->Init()) { LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR, "Failed to initialize ChannelManager."); } return RTCError::OK(); } std::unique_ptr OrtcFactory::CreateMediaEngine_w() { RTC_DCHECK_RUN_ON(worker_thread_.get()); // The null arguments are optional factories that could be passed into the // OrtcFactory, but aren't yet. // // Note that |adm_| may be null, in which case the platform-specific default // AudioDeviceModule will be used. return std::unique_ptr( cricket::WebRtcMediaEngineFactory::Create( rtc::scoped_refptr(adm_), audio_encoder_factory_, audio_decoder_factory_, webrtc::CreateBuiltinVideoEncoderFactory(), webrtc::CreateBuiltinVideoDecoderFactory(), nullptr, webrtc::AudioProcessingBuilder().Create())); } } // namespace webrtc