| Index: webrtc/ortc/ortcfactory.cc | 
| diff --git a/webrtc/ortc/ortcfactory.cc b/webrtc/ortc/ortcfactory.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..c0d54d16f05d43d57c92d5b6a8526026f6c73b4f | 
| --- /dev/null | 
| +++ b/webrtc/ortc/ortcfactory.cc | 
| @@ -0,0 +1,504 @@ | 
| +/* | 
| + *  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 "webrtc/ortc/ortcfactory.h" | 
| + | 
| +#include <sstream> | 
| +#include <vector> | 
| +#include <utility>  // For std::move. | 
| + | 
| +#include "webrtc/api/proxy.h" | 
| +#include "webrtc/api/mediastreamtrackproxy.h" | 
| +#include "webrtc/api/rtcerror.h" | 
| +#include "webrtc/api/videosourceproxy.h" | 
| +#include "webrtc/base/asyncpacketsocket.h" | 
| +#include "webrtc/base/bind.h" | 
| +#include "webrtc/base/checks.h" | 
| +#include "webrtc/base/helpers.h" | 
| +#include "webrtc/base/logging.h" | 
| +#include "webrtc/logging/rtc_event_log/rtc_event_log.h" | 
| +#include "webrtc/media/base/mediaconstants.h" | 
| +#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h" | 
| +#include "webrtc/ortc/ortcrtpreceiveradapter.h" | 
| +#include "webrtc/ortc/ortcrtpsenderadapter.h" | 
| +#include "webrtc/ortc/rtpparametersconversion.h" | 
| +#include "webrtc/ortc/rtptransportadapter.h" | 
| +#include "webrtc/ortc/rtptransportcontrolleradapter.h" | 
| +#include "webrtc/p2p/base/basicpacketsocketfactory.h" | 
| +#include "webrtc/p2p/base/udptransport.h" | 
| +#include "webrtc/pc/channelmanager.h" | 
| +#include "webrtc/pc/localaudiosource.h" | 
| +#include "webrtc/pc/audiotrack.h" | 
| +#include "webrtc/pc/videocapturertracksource.h" | 
| +#include "webrtc/pc/videotrack.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 <typename C> | 
| +webrtc::RtpCapabilities ToRtpCapabilitiesWithAsserts( | 
| +    const std::vector<C>& 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<std::unique_ptr<RtpTransportControllerInterface>>, | 
| +              CreateRtpTransportController) | 
| +PROXY_METHOD4(RTCErrorOr<std::unique_ptr<RtpTransportInterface>>, | 
| +              CreateRtpTransport, | 
| +              const RtcpParameters&, | 
| +              PacketTransportInterface*, | 
| +              PacketTransportInterface*, | 
| +              RtpTransportControllerInterface*) | 
| +PROXY_CONSTMETHOD1(RtpCapabilities, | 
| +                   GetRtpSenderCapabilities, | 
| +                   cricket::MediaType) | 
| +PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>, | 
| +              CreateRtpSender, | 
| +              rtc::scoped_refptr<MediaStreamTrackInterface>, | 
| +              RtpTransportInterface*) | 
| +PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>, | 
| +              CreateRtpSender, | 
| +              cricket::MediaType, | 
| +              RtpTransportInterface*) | 
| +PROXY_CONSTMETHOD1(RtpCapabilities, | 
| +                   GetRtpReceiverCapabilities, | 
| +                   cricket::MediaType) | 
| +PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpReceiverInterface>>, | 
| +              CreateRtpReceiver, | 
| +              cricket::MediaType, | 
| +              RtpTransportInterface*) | 
| +PROXY_WORKER_METHOD3(RTCErrorOr<std::unique_ptr<UdpTransportInterface>>, | 
| +                     CreateUdpTransport, | 
| +                     int, | 
| +                     uint16_t, | 
| +                     uint16_t) | 
| +PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>, | 
| +              CreateAudioSource, | 
| +              const cricket::AudioOptions&) | 
| +PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>, | 
| +              CreateVideoSource, | 
| +              std::unique_ptr<cricket::VideoCapturer>, | 
| +              const MediaConstraintsInterface*) | 
| +PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>, | 
| +              CreateVideoTrack, | 
| +              const std::string&, | 
| +              VideoTrackSourceInterface*) | 
| +PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>, | 
| +              CreateAudioTrack, | 
| +              const std::string&, | 
| +              AudioSourceInterface*) | 
| +END_PROXY_MAP() | 
| + | 
| +// static | 
| +RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>> OrtcFactory::Create( | 
| +    rtc::Thread* network_thread, | 
| +    rtc::Thread* signaling_thread, | 
| +    rtc::NetworkManager* network_manager, | 
| +    rtc::PacketSocketFactory* socket_factory, | 
| +    AudioDeviceModule* adm, | 
| +    std::unique_ptr<cricket::MediaEngineInterface> media_engine) { | 
| +  // Hop to signaling thread if needed. | 
| +  if (signaling_thread && !signaling_thread->IsCurrent()) { | 
| +    return signaling_thread | 
| +        ->Invoke<RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>>>( | 
| +            RTC_FROM_HERE, | 
| +            rtc::Bind(&OrtcFactory::Create_s, network_thread, signaling_thread, | 
| +                      network_manager, socket_factory, adm, | 
| +                      media_engine.release())); | 
| +  } | 
| +  return Create_s(network_thread, signaling_thread, network_manager, | 
| +                  socket_factory, adm, media_engine.release()); | 
| +} | 
| + | 
| +RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>> OrtcFactoryInterface::Create( | 
| +    rtc::Thread* network_thread, | 
| +    rtc::Thread* signaling_thread, | 
| +    rtc::NetworkManager* network_manager, | 
| +    rtc::PacketSocketFactory* socket_factory, | 
| +    AudioDeviceModule* adm) { | 
| +  return OrtcFactory::Create(network_thread, signaling_thread, network_manager, | 
| +                             socket_factory, adm, nullptr); | 
| +} | 
| + | 
| +OrtcFactory::OrtcFactory(rtc::Thread* network_thread, | 
| +                         rtc::Thread* signaling_thread, | 
| +                         rtc::NetworkManager* network_manager, | 
| +                         rtc::PacketSocketFactory* socket_factory, | 
| +                         AudioDeviceModule* adm) | 
| +    : network_thread_(network_thread), | 
| +      signaling_thread_(signaling_thread), | 
| +      network_manager_(network_manager), | 
| +      socket_factory_(socket_factory), | 
| +      adm_(adm), | 
| +      null_event_log_(RtcEventLog::CreateNull()), | 
| +      audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()) { | 
| +  if (!rtc::CreateRandomString(kDefaultRtcpCnameLength, &default_cname_)) { | 
| +    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_->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 (!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<std::unique_ptr<RtpTransportControllerInterface>> | 
| +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()); | 
| +} | 
| + | 
| +RTCErrorOr<std::unique_ptr<RtpTransportInterface>> | 
| +OrtcFactory::CreateRtpTransport( | 
| +    const RtcpParameters& rtcp_parameters, | 
| +    PacketTransportInterface* rtp, | 
| +    PacketTransportInterface* rtcp, | 
| +    RtpTransportControllerInterface* transport_controller) { | 
| +  RTC_DCHECK_RUN_ON(signaling_thread_); | 
| +  RtcpParameters copied_parameters = rtcp_parameters; | 
| +  if (copied_parameters.cname.empty()) { | 
| +    copied_parameters.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; | 
| +  } | 
| +} | 
| + | 
| +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<std::unique_ptr<OrtcRtpSenderInterface>> | 
| +OrtcFactory::CreateRtpSender( | 
| +    rtc::scoped_refptr<MediaStreamTrackInterface> 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<std::unique_ptr<OrtcRtpSenderInterface>> | 
| +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<std::unique_ptr<OrtcRtpReceiverInterface>> | 
| +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<std::unique_ptr<UdpTransportInterface>> | 
| +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<rtc::AsyncPacketSocket> 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); | 
| +  } | 
| +  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<cricket::UdpTransport>::Create( | 
| +      signaling_thread_, network_thread_, | 
| +      std::unique_ptr<cricket::UdpTransport>( | 
| +          new cricket::UdpTransport(oss.str(), std::move(socket)))); | 
| +} | 
| + | 
| +rtc::scoped_refptr<AudioSourceInterface> OrtcFactory::CreateAudioSource( | 
| +    const cricket::AudioOptions& options) { | 
| +  RTC_DCHECK_RUN_ON(signaling_thread_); | 
| +  return rtc::scoped_refptr<LocalAudioSource>( | 
| +      LocalAudioSource::Create(&options)); | 
| +} | 
| + | 
| +rtc::scoped_refptr<VideoTrackSourceInterface> OrtcFactory::CreateVideoSource( | 
| +    std::unique_ptr<cricket::VideoCapturer> capturer, | 
| +    const MediaConstraintsInterface* constraints) { | 
| +  RTC_DCHECK_RUN_ON(signaling_thread_); | 
| +  rtc::scoped_refptr<VideoTrackSourceInterface> source( | 
| +      VideoCapturerTrackSource::Create( | 
| +          worker_thread_.get(), std::move(capturer), constraints, false)); | 
| +  return VideoTrackSourceProxy::Create(signaling_thread_, worker_thread_.get(), | 
| +                                       source); | 
| +} | 
| + | 
| +rtc::scoped_refptr<VideoTrackInterface> OrtcFactory::CreateVideoTrack( | 
| +    const std::string& id, | 
| +    VideoTrackSourceInterface* source) { | 
| +  RTC_DCHECK_RUN_ON(signaling_thread_); | 
| +  rtc::scoped_refptr<VideoTrackInterface> track(VideoTrack::Create(id, source)); | 
| +  return VideoTrackProxy::Create(signaling_thread_, worker_thread_.get(), | 
| +                                 track); | 
| +} | 
| + | 
| +rtc::scoped_refptr<AudioTrackInterface> OrtcFactory::CreateAudioTrack( | 
| +    const std::string& id, | 
| +    AudioSourceInterface* source) { | 
| +  RTC_DCHECK_RUN_ON(signaling_thread_); | 
| +  rtc::scoped_refptr<AudioTrackInterface> track(AudioTrack::Create(id, source)); | 
| +  return AudioTrackProxy::Create(signaling_thread_, track); | 
| +} | 
| + | 
| +// static | 
| +RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>> 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) { | 
| +  // Add the unique_ptr wrapper back. | 
| +  std::unique_ptr<cricket::MediaEngineInterface> owned_media_engine( | 
| +      media_engine); | 
| +  std::unique_ptr<OrtcFactory> new_factory(new OrtcFactory( | 
| +      network_thread, signaling_thread, network_manager, socket_factory, adm)); | 
| +  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<cricket::MediaEngineInterface> 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<std::unique_ptr<cricket::MediaEngineInterface>>( | 
| +            RTC_FROM_HERE, rtc::Bind(&OrtcFactory::CreateMediaEngine_w, this)); | 
| +  } | 
| + | 
| +  channel_manager_.reset(new cricket::ChannelManager( | 
| +      std::move(media_engine), 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<cricket::MediaEngineInterface> | 
| +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::MediaEngineInterface>( | 
| +      cricket::WebRtcMediaEngineFactory::Create(adm_, audio_decoder_factory_, | 
| +                                                nullptr, nullptr, nullptr)); | 
| +} | 
| + | 
| +}  // namespace webrtc | 
|  |