OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "webrtc/ortc/ortcfactory.h" |
| 12 |
| 13 #include <vector> |
| 14 #include <utility> // For std::move. |
| 15 |
| 16 #include "webrtc/api/proxy.h" |
| 17 #include "webrtc/api/mediastreamtrackproxy.h" |
| 18 #include "webrtc/api/videosourceproxy.h" |
| 19 #include "webrtc/base/bind.h" |
| 20 #include "webrtc/base/asyncpacketsocket.h" |
| 21 #include "webrtc/base/logging.h" |
| 22 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" |
| 23 #include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h" |
| 24 #include "webrtc/ortc/rtpreceivershim.h" |
| 25 #include "webrtc/ortc/rtpsendershim.h" |
| 26 #include "webrtc/ortc/rtptransportcontrollershim.h" |
| 27 #include "webrtc/ortc/rtptransportshim.h" |
| 28 #include "webrtc/p2p/base/basicpacketsocketfactory.h" |
| 29 #include "webrtc/p2p/base/udptransport.h" |
| 30 #include "webrtc/pc/channelmanager.h" |
| 31 #include "webrtc/pc/localaudiosource.h" |
| 32 #include "webrtc/pc/audiotrack.h" |
| 33 #include "webrtc/pc/videocapturertracksource.h" |
| 34 #include "webrtc/pc/videotrack.h" |
| 35 |
| 36 namespace { |
| 37 |
| 38 void ConvertFeedbackParam(const cricket::FeedbackParam& cricket_feedback, |
| 39 webrtc::RtpCodecCapability* codec) { |
| 40 if (cricket_feedback.id() == "ack") { |
| 41 RTC_DCHECK(cricket_feedback.param().empty()); |
| 42 codec->rtcp_feedback.emplace_back(webrtc::RtcpFeedbackType::ACK); |
| 43 } else if (cricket_feedback.id() == "ccm") { |
| 44 if (cricket_feedback.param() == "fir") { |
| 45 codec->rtcp_feedback.emplace_back(webrtc::RtcpFeedbackType::CCM, |
| 46 webrtc::RtcpFeedbackMessageType::FIR); |
| 47 } else { |
| 48 RTC_NOTREACHED(); |
| 49 } |
| 50 } else if (cricket_feedback.id() == "nack") { |
| 51 if (cricket_feedback.param().empty()) { |
| 52 codec->rtcp_feedback.emplace_back( |
| 53 webrtc::RtcpFeedbackType::NACK, |
| 54 webrtc::RtcpFeedbackMessageType::GENERIC_NACK); |
| 55 } else if (cricket_feedback.param() == "pli") { |
| 56 codec->rtcp_feedback.emplace_back(webrtc::RtcpFeedbackType::NACK, |
| 57 webrtc::RtcpFeedbackMessageType::PLI); |
| 58 } else { |
| 59 RTC_NOTREACHED(); |
| 60 } |
| 61 } else if (cricket_feedback.id() == "goog-remb") { |
| 62 RTC_DCHECK(cricket_feedback.param().empty()); |
| 63 codec->rtcp_feedback.emplace_back(webrtc::RtcpFeedbackType::REMB); |
| 64 } else if (cricket_feedback.id() == "transport-cc") { |
| 65 RTC_DCHECK(cricket_feedback.param().empty()); |
| 66 codec->rtcp_feedback.emplace_back(webrtc::RtcpFeedbackType::TRANSPORT_CC); |
| 67 } else { |
| 68 RTC_NOTREACHED(); |
| 69 } |
| 70 } |
| 71 |
| 72 template <typename C> |
| 73 void CodecSpecificConversion(const C& cricket_codec, |
| 74 webrtc::RtpCodecCapability* codec) {} |
| 75 |
| 76 template <> |
| 77 void CodecSpecificConversion<cricket::AudioCodec>( |
| 78 const cricket::AudioCodec& cricket_codec, |
| 79 webrtc::RtpCodecCapability* codec) { |
| 80 codec->num_channels = rtc::Optional<int>(cricket_codec.channels); |
| 81 } |
| 82 |
| 83 template <class C> |
| 84 webrtc::RtpCapabilities ConvertCapabilities( |
| 85 cricket::MediaType kind, |
| 86 const std::vector<C> cricket_codecs, |
| 87 const cricket::RtpHeaderExtensions& cricket_extensions) { |
| 88 webrtc::RtpCapabilities capabilities; |
| 89 bool have_red = false; |
| 90 bool have_ulpfec = false; |
| 91 bool have_flexfec = false; |
| 92 for (const C& cricket_codec : cricket_codecs) { |
| 93 if (cricket_codec.name == "red") { |
| 94 have_red = true; |
| 95 } else if (cricket_codec.name == "ulpfec") { |
| 96 have_ulpfec = true; |
| 97 } else if (cricket_codec.name == "flexfec") { |
| 98 have_flexfec = true; |
| 99 } |
| 100 webrtc::RtpCodecCapability codec; |
| 101 codec.name = cricket_codec.name; |
| 102 codec.kind = kind; |
| 103 codec.clock_rate = rtc::Optional<int>(cricket_codec.clockrate); |
| 104 codec.preferred_payload_type = rtc::Optional<int>(cricket_codec.id); |
| 105 for (const cricket::FeedbackParam& cricket_feedback : |
| 106 cricket_codec.feedback_params.params()) { |
| 107 ConvertFeedbackParam(cricket_feedback, &codec); |
| 108 } |
| 109 CodecSpecificConversion(cricket_codec, &codec); |
| 110 codec.parameters.insert(cricket_codec.params.begin(), |
| 111 cricket_codec.params.end()); |
| 112 capabilities.codecs.push_back(std::move(codec)); |
| 113 } |
| 114 for (const webrtc::RtpExtension& cricket_extension : cricket_extensions) { |
| 115 capabilities.header_extensions.emplace_back(cricket_extension.uri, |
| 116 cricket_extension.id); |
| 117 } |
| 118 if (have_red) { |
| 119 capabilities.fec.push_back(webrtc::FecMechanism::RED); |
| 120 } |
| 121 if (have_red && have_ulpfec) { |
| 122 capabilities.fec.push_back(webrtc::FecMechanism::RED_AND_ULPFEC); |
| 123 } |
| 124 if (have_flexfec) { |
| 125 capabilities.fec.push_back(webrtc::FecMechanism::FLEXFEC); |
| 126 } |
| 127 return capabilities; |
| 128 } |
| 129 |
| 130 } // namespace |
| 131 |
| 132 namespace webrtc { |
| 133 |
| 134 // Note that this proxy class uses the network thread as the "worker" thread. |
| 135 BEGIN_OWNED_PROXY_MAP(OrtcFactory) |
| 136 PROXY_SIGNALING_THREAD_DESTRUCTOR() |
| 137 PROXY_METHOD0(RTCErrorOr<std::unique_ptr<RtpTransportControllerInterface>>, |
| 138 CreateRtpTransportController) |
| 139 PROXY_METHOD4(RTCErrorOr<std::unique_ptr<RtpTransportInterface>>, |
| 140 CreateRtpTransport, |
| 141 const RtcpParameters&, |
| 142 PacketTransportInterface*, |
| 143 PacketTransportInterface*, |
| 144 RtpTransportControllerInterface*) |
| 145 PROXY_CONSTMETHOD1(RtpCapabilities, |
| 146 GetRtpSenderCapabilities, |
| 147 cricket::MediaType) |
| 148 PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>, |
| 149 CreateRtpSender, |
| 150 rtc::scoped_refptr<MediaStreamTrackInterface>, |
| 151 RtpTransportInterface*) |
| 152 PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>, |
| 153 CreateRtpSender, |
| 154 cricket::MediaType, |
| 155 RtpTransportInterface*) |
| 156 PROXY_CONSTMETHOD1(RtpCapabilities, |
| 157 GetRtpReceiverCapabilities, |
| 158 cricket::MediaType) |
| 159 PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpReceiverInterface>>, |
| 160 CreateRtpReceiver, |
| 161 cricket::MediaType, |
| 162 RtpTransportInterface*) |
| 163 PROXY_WORKER_METHOD3(RTCErrorOr<std::unique_ptr<UdpTransportInterface>>, |
| 164 CreateUdpTransport, |
| 165 int, |
| 166 uint16_t, |
| 167 uint16_t) |
| 168 PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>, |
| 169 CreateAudioSource, |
| 170 const cricket::AudioOptions&) |
| 171 PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>, |
| 172 CreateVideoSource, |
| 173 std::unique_ptr<cricket::VideoCapturer>, |
| 174 const MediaConstraintsInterface*) |
| 175 PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>, |
| 176 CreateVideoTrack, |
| 177 const std::string&, |
| 178 VideoTrackSourceInterface*) |
| 179 PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>, |
| 180 CreateAudioTrack, |
| 181 const std::string&, |
| 182 AudioSourceInterface*) |
| 183 END_PROXY_MAP() |
| 184 |
| 185 // static |
| 186 RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>> OrtcFactoryInterface::Create( |
| 187 rtc::Thread* network_thread, |
| 188 rtc::Thread* signaling_thread, |
| 189 rtc::NetworkManager* network_manager, |
| 190 rtc::PacketSocketFactory* socket_factory, |
| 191 AudioDeviceModule* adm) { |
| 192 // Hop to signaling thread if needed. |
| 193 if (signaling_thread && !signaling_thread->IsCurrent()) { |
| 194 return signaling_thread |
| 195 ->Invoke<RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>>>( |
| 196 RTC_FROM_HERE, |
| 197 rtc::Bind(&OrtcFactoryInterface::Create, network_thread, |
| 198 signaling_thread, network_manager, socket_factory, adm)); |
| 199 } |
| 200 std::unique_ptr<OrtcFactory> new_factory(new OrtcFactory( |
| 201 network_thread, signaling_thread, network_manager, socket_factory, adm)); |
| 202 RTCError err = new_factory->Initialize(); |
| 203 if (!err.ok()) { |
| 204 return err; |
| 205 } |
| 206 // Return a proxy so that any calls on the returned object (including |
| 207 // destructor) happen on the signaling thread. |
| 208 return OrtcFactoryProxy::Create(new_factory->signaling_thread(), |
| 209 new_factory->network_thread(), |
| 210 new_factory.release()); |
| 211 } |
| 212 |
| 213 OrtcFactory::OrtcFactory(rtc::Thread* network_thread, |
| 214 rtc::Thread* signaling_thread, |
| 215 rtc::NetworkManager* network_manager, |
| 216 rtc::PacketSocketFactory* socket_factory, |
| 217 AudioDeviceModule* adm) |
| 218 : network_thread_(network_thread), |
| 219 signaling_thread_(signaling_thread), |
| 220 network_manager_(network_manager), |
| 221 socket_factory_(socket_factory), |
| 222 adm_(adm), |
| 223 null_event_log_(RtcEventLog::CreateNull()), |
| 224 audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()) { |
| 225 if (!network_thread_) { |
| 226 owned_network_thread_ = rtc::Thread::CreateWithSocketServer(); |
| 227 owned_network_thread_->Start(); |
| 228 network_thread_ = owned_network_thread_.get(); |
| 229 } |
| 230 |
| 231 // The worker thread is created internally because it's an implementation |
| 232 // detail, and consumers of the API don't need to really know about it. |
| 233 worker_thread_ = rtc::Thread::Create(); |
| 234 worker_thread_->Start(); |
| 235 |
| 236 if (signaling_thread_) { |
| 237 RTC_DCHECK_RUN_ON(signaling_thread_); |
| 238 } else { |
| 239 signaling_thread_ = rtc::Thread::Current(); |
| 240 if (!signaling_thread_) { |
| 241 // If this thread isn't already wrapped by an rtc::Thread, create a |
| 242 // wrapper and own it in this class. |
| 243 signaling_thread_ = rtc::ThreadManager::Instance()->WrapCurrentThread(); |
| 244 wraps_signaling_thread_ = true; |
| 245 } |
| 246 } |
| 247 if (!network_manager_) { |
| 248 owned_network_manager_.reset(new rtc::BasicNetworkManager()); |
| 249 network_manager_ = owned_network_manager_.get(); |
| 250 } |
| 251 if (!socket_factory_) { |
| 252 owned_socket_factory_.reset( |
| 253 new rtc::BasicPacketSocketFactory(network_thread_)); |
| 254 socket_factory_ = owned_socket_factory_.get(); |
| 255 } |
| 256 } |
| 257 |
| 258 OrtcFactory::~OrtcFactory() { |
| 259 RTC_DCHECK_RUN_ON(signaling_thread_); |
| 260 if (wraps_signaling_thread_) { |
| 261 rtc::ThreadManager::Instance()->UnwrapCurrentThread(); |
| 262 } |
| 263 } |
| 264 |
| 265 RTCErrorOr<std::unique_ptr<RtpTransportControllerInterface>> |
| 266 OrtcFactory::CreateRtpTransportController() { |
| 267 return RtpTransportControllerShim::CreateProxied( |
| 268 cricket::MediaConfig(), channel_manager_.get(), null_event_log_.get(), |
| 269 signaling_thread_, worker_thread_.get()); |
| 270 } |
| 271 |
| 272 RTCErrorOr<std::unique_ptr<RtpTransportInterface>> |
| 273 OrtcFactory::CreateRtpTransport( |
| 274 const RtcpParameters& rtcp_parameters, |
| 275 PacketTransportInterface* rtp, |
| 276 PacketTransportInterface* rtcp, |
| 277 RtpTransportControllerInterface* transport_controller) { |
| 278 if (transport_controller) { |
| 279 return RtpTransportShim::CreateProxied(rtcp_parameters, rtp, rtcp, |
| 280 transport_controller); |
| 281 } else { |
| 282 // If |transport_controller| is null, create one automatically, which the |
| 283 // returned RtpTransport will own. |
| 284 auto result = CreateRtpTransportController(); |
| 285 if (!result.ok()) { |
| 286 return result.error(); |
| 287 } |
| 288 return RtpTransportShim::CreateProxied(rtcp_parameters, rtp, rtcp, |
| 289 result.MoveValue()); |
| 290 } |
| 291 } |
| 292 |
| 293 RtpCapabilities OrtcFactory::GetRtpSenderCapabilities( |
| 294 cricket::MediaType kind) const { |
| 295 switch (kind) { |
| 296 case cricket::MEDIA_TYPE_AUDIO: { |
| 297 cricket::AudioCodecs cricket_codecs; |
| 298 cricket::RtpHeaderExtensions cricket_extensions; |
| 299 channel_manager_->GetSupportedAudioSendCodecs(&cricket_codecs); |
| 300 channel_manager_->GetSupportedAudioRtpHeaderExtensions( |
| 301 &cricket_extensions); |
| 302 return ConvertCapabilities(kind, cricket_codecs, cricket_extensions); |
| 303 } |
| 304 case cricket::MEDIA_TYPE_VIDEO: { |
| 305 cricket::VideoCodecs cricket_codecs; |
| 306 cricket::RtpHeaderExtensions cricket_extensions; |
| 307 channel_manager_->GetSupportedVideoCodecs(&cricket_codecs); |
| 308 channel_manager_->GetSupportedVideoRtpHeaderExtensions( |
| 309 &cricket_extensions); |
| 310 return ConvertCapabilities(kind, cricket_codecs, cricket_extensions); |
| 311 } |
| 312 case cricket::MEDIA_TYPE_DATA: |
| 313 return RtpCapabilities(); |
| 314 } |
| 315 } |
| 316 |
| 317 RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>> |
| 318 OrtcFactory::CreateRtpSender( |
| 319 rtc::scoped_refptr<MediaStreamTrackInterface> track, |
| 320 RtpTransportInterface* transport) { |
| 321 if (!track) { |
| 322 return CreateAndLogError(RTCErrorType::INVALID_PARAMETER, |
| 323 "Cannot pass null track into CreateRtpSender."); |
| 324 } |
| 325 auto result = |
| 326 CreateRtpSender(cricket::MediaTypeFromString(track->kind()), transport); |
| 327 if (!result.ok()) { |
| 328 return result; |
| 329 } |
| 330 auto err = result.value()->SetTrack(track); |
| 331 if (!err.ok()) { |
| 332 return err; |
| 333 } |
| 334 return result; |
| 335 } |
| 336 |
| 337 RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>> |
| 338 OrtcFactory::CreateRtpSender(cricket::MediaType kind, |
| 339 RtpTransportInterface* transport) { |
| 340 if (kind == cricket::MEDIA_TYPE_DATA) { |
| 341 return CreateAndLogError(RTCErrorType::INVALID_PARAMETER, |
| 342 "Cannot create data RtpSender."); |
| 343 } |
| 344 if (!transport) { |
| 345 return CreateAndLogError( |
| 346 RTCErrorType::INVALID_PARAMETER, |
| 347 "Cannot pass null transport into CreateRtpSender."); |
| 348 } |
| 349 return RtpSenderShim::CreateProxied(kind, transport->GetInternal()); |
| 350 } |
| 351 |
| 352 RtpCapabilities OrtcFactory::GetRtpReceiverCapabilities( |
| 353 cricket::MediaType kind) const { |
| 354 switch (kind) { |
| 355 case cricket::MEDIA_TYPE_AUDIO: { |
| 356 cricket::AudioCodecs cricket_codecs; |
| 357 cricket::RtpHeaderExtensions cricket_extensions; |
| 358 channel_manager_->GetSupportedAudioReceiveCodecs(&cricket_codecs); |
| 359 channel_manager_->GetSupportedAudioRtpHeaderExtensions( |
| 360 &cricket_extensions); |
| 361 return ConvertCapabilities(kind, cricket_codecs, cricket_extensions); |
| 362 } |
| 363 case cricket::MEDIA_TYPE_VIDEO: { |
| 364 cricket::VideoCodecs cricket_codecs; |
| 365 cricket::RtpHeaderExtensions cricket_extensions; |
| 366 channel_manager_->GetSupportedVideoCodecs(&cricket_codecs); |
| 367 channel_manager_->GetSupportedVideoRtpHeaderExtensions( |
| 368 &cricket_extensions); |
| 369 return ConvertCapabilities(kind, cricket_codecs, cricket_extensions); |
| 370 } |
| 371 case cricket::MEDIA_TYPE_DATA: |
| 372 return RtpCapabilities(); |
| 373 } |
| 374 } |
| 375 |
| 376 RTCErrorOr<std::unique_ptr<OrtcRtpReceiverInterface>> |
| 377 OrtcFactory::CreateRtpReceiver(cricket::MediaType kind, |
| 378 RtpTransportInterface* transport) { |
| 379 if (kind == cricket::MEDIA_TYPE_DATA) { |
| 380 return CreateAndLogError(RTCErrorType::INVALID_PARAMETER, |
| 381 "Cannot create data RtpReceiver."); |
| 382 } |
| 383 if (!transport) { |
| 384 return CreateAndLogError( |
| 385 RTCErrorType::INVALID_PARAMETER, |
| 386 "Cannot pass null transport into CreateRtpReceiver."); |
| 387 } |
| 388 return RtpReceiverShim::CreateProxied(kind, transport->GetInternal()); |
| 389 } |
| 390 |
| 391 BEGIN_OWNED_PROXY_MAP(UdpTransport) |
| 392 PROXY_WORKER_THREAD_DESTRUCTOR() |
| 393 PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetLocalAddress) |
| 394 PROXY_WORKER_METHOD1(bool, SetRemoteAddress, const rtc::SocketAddress&) |
| 395 PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetRemoteAddress) |
| 396 protected: |
| 397 rtc::PacketTransportInternal* GetInternal() override { |
| 398 return internal(); |
| 399 } |
| 400 END_PROXY_MAP() |
| 401 |
| 402 RTCErrorOr<std::unique_ptr<UdpTransportInterface>> |
| 403 OrtcFactory::CreateUdpTransport(int family, |
| 404 uint16_t min_port, |
| 405 uint16_t max_port) { |
| 406 RTC_DCHECK_RUN_ON(network_thread_); |
| 407 std::unique_ptr<rtc::AsyncPacketSocket> socket( |
| 408 socket_factory_->CreateUdpSocket( |
| 409 rtc::SocketAddress(rtc::GetAnyIP(family), 0), min_port, max_port)); |
| 410 if (!socket) { |
| 411 // Only log at warning level, because this method may be called with |
| 412 // specific port ranges to determine if a port is available, expecting the |
| 413 // possibility of an error. |
| 414 return CreateAndLogError(RTCErrorType::RESOURCE_EXHAUSTED, |
| 415 "Local socket allocation failure.", |
| 416 rtc::LS_WARNING); |
| 417 } |
| 418 LOG(LS_INFO) << "Created UDP socket with address " |
| 419 << socket->GetLocalAddress().ToSensitiveString() << "."; |
| 420 // Use proxy so that calls to the returned object are invoked on the network |
| 421 // thread. |
| 422 return UdpTransportProxyWithInternal<cricket::UdpTransport>::Create( |
| 423 signaling_thread_, network_thread_, |
| 424 new cricket::UdpTransport(std::string(), std::move(socket))); |
| 425 } |
| 426 |
| 427 rtc::scoped_refptr<AudioSourceInterface> OrtcFactory::CreateAudioSource( |
| 428 const cricket::AudioOptions& options) { |
| 429 RTC_DCHECK_RUN_ON(signaling_thread_); |
| 430 return rtc::scoped_refptr<LocalAudioSource>( |
| 431 LocalAudioSource::Create(&options)); |
| 432 } |
| 433 |
| 434 rtc::scoped_refptr<VideoTrackSourceInterface> OrtcFactory::CreateVideoSource( |
| 435 std::unique_ptr<cricket::VideoCapturer> capturer, |
| 436 const MediaConstraintsInterface* constraints) { |
| 437 RTC_DCHECK_RUN_ON(signaling_thread_); |
| 438 rtc::scoped_refptr<VideoTrackSourceInterface> source( |
| 439 VideoCapturerTrackSource::Create( |
| 440 worker_thread_.get(), std::move(capturer), constraints, false)); |
| 441 return VideoTrackSourceProxy::Create(signaling_thread_, worker_thread_.get(), |
| 442 source); |
| 443 } |
| 444 |
| 445 rtc::scoped_refptr<VideoTrackInterface> OrtcFactory::CreateVideoTrack( |
| 446 const std::string& id, |
| 447 VideoTrackSourceInterface* source) { |
| 448 RTC_DCHECK_RUN_ON(signaling_thread_); |
| 449 rtc::scoped_refptr<VideoTrackInterface> track(VideoTrack::Create(id, source)); |
| 450 return VideoTrackProxy::Create(signaling_thread_, worker_thread_.get(), |
| 451 track); |
| 452 } |
| 453 |
| 454 rtc::scoped_refptr<AudioTrackInterface> OrtcFactory::CreateAudioTrack( |
| 455 const std::string& id, |
| 456 AudioSourceInterface* source) { |
| 457 RTC_DCHECK_RUN_ON(signaling_thread_); |
| 458 rtc::scoped_refptr<AudioTrackInterface> track(AudioTrack::Create(id, source)); |
| 459 return AudioTrackProxy::Create(signaling_thread_, track); |
| 460 } |
| 461 |
| 462 RTCError OrtcFactory::Initialize() { |
| 463 // TODO(deadbeef): Get rid of requirement to hop to worker thread here. |
| 464 std::unique_ptr<cricket::MediaEngineInterface> media_engine = |
| 465 worker_thread_->Invoke<std::unique_ptr<cricket::MediaEngineInterface>>( |
| 466 RTC_FROM_HERE, rtc::Bind(&OrtcFactory::CreateMediaEngine_w, this)); |
| 467 |
| 468 channel_manager_.reset(new cricket::ChannelManager( |
| 469 std::move(media_engine), worker_thread_.get(), network_thread_)); |
| 470 channel_manager_->SetVideoRtxEnabled(true); |
| 471 if (!channel_manager_->Init()) { |
| 472 return CreateAndLogError(RTCErrorType::INTERNAL_ERROR, |
| 473 "Failed to initialize ChannelManager."); |
| 474 } |
| 475 return RTCError(); |
| 476 } |
| 477 |
| 478 std::unique_ptr<cricket::MediaEngineInterface> |
| 479 OrtcFactory::CreateMediaEngine_w() { |
| 480 RTC_DCHECK_RUN_ON(worker_thread_.get()); |
| 481 // The nullptr arguments are optional factories that could be passed into the |
| 482 // OrtcFactory, but aren't yet. |
| 483 // Note that |adm_| may be null. |
| 484 return std::unique_ptr<cricket::MediaEngineInterface>( |
| 485 cricket::WebRtcMediaEngineFactory::Create(adm_, audio_decoder_factory_, |
| 486 nullptr, nullptr, nullptr)); |
| 487 } |
| 488 |
| 489 } // namespace webrtc |
OLD | NEW |