Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: webrtc/ortc/ortcfactory.cc

Issue 2714813004: Create the SrtpTransportInterface. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 <sstream>
14 #include <vector>
15 #include <utility> // For std::move.
16
17 #include "webrtc/api/proxy.h"
18 #include "webrtc/api/mediastreamtrackproxy.h"
19 #include "webrtc/api/rtcerror.h"
20 #include "webrtc/api/videosourceproxy.h"
21 #include "webrtc/base/asyncpacketsocket.h"
22 #include "webrtc/base/bind.h"
23 #include "webrtc/base/checks.h"
24 #include "webrtc/base/helpers.h"
25 #include "webrtc/base/logging.h"
26 #include "webrtc/logging/rtc_event_log/rtc_event_log.h"
27 #include "webrtc/media/base/mediaconstants.h"
28 #include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
29 #include "webrtc/ortc/ortcrtpreceiveradapter.h"
30 #include "webrtc/ortc/ortcrtpsenderadapter.h"
31 #include "webrtc/ortc/rtpparametersconversion.h"
32 #include "webrtc/ortc/rtptransportadapter.h"
33 #include "webrtc/ortc/rtptransportcontrolleradapter.h"
34 #include "webrtc/p2p/base/basicpacketsocketfactory.h"
35 #include "webrtc/p2p/base/udptransport.h"
36 #include "webrtc/pc/channelmanager.h"
37 #include "webrtc/pc/localaudiosource.h"
38 #include "webrtc/pc/audiotrack.h"
39 #include "webrtc/pc/videocapturertracksource.h"
40 #include "webrtc/pc/videotrack.h"
41
42 namespace {
43
44 const int kDefaultRtcpCnameLength = 16;
45
46 // Asserts that all of the built-in capabilities can be converted to
47 // RtpCapabilities. If they can't, something's wrong (for example, maybe a new
48 // feedback mechanism is supported, but an enum value wasn't added to
49 // rtpparameters.h).
50 template <typename C>
51 webrtc::RtpCapabilities ToRtpCapabilitiesWithAsserts(
52 const std::vector<C>& cricket_codecs,
53 const cricket::RtpHeaderExtensions& cricket_extensions) {
54 webrtc::RtpCapabilities capabilities =
55 webrtc::ToRtpCapabilities(cricket_codecs, cricket_extensions);
56 RTC_DCHECK_EQ(capabilities.codecs.size(), cricket_codecs.size());
57 for (size_t i = 0; i < capabilities.codecs.size(); ++i) {
58 RTC_DCHECK_EQ(capabilities.codecs[i].rtcp_feedback.size(),
59 cricket_codecs[i].feedback_params.params().size());
60 }
61 RTC_DCHECK_EQ(capabilities.header_extensions.size(),
62 cricket_extensions.size());
63 return capabilities;
64 }
65
66 } // namespace
67
68 namespace webrtc {
69
70 // Note that this proxy class uses the network thread as the "worker" thread.
71 BEGIN_OWNED_PROXY_MAP(OrtcFactory)
72 PROXY_SIGNALING_THREAD_DESTRUCTOR()
73 PROXY_METHOD0(RTCErrorOr<std::unique_ptr<RtpTransportControllerInterface>>,
74 CreateRtpTransportController)
75 PROXY_METHOD4(RTCErrorOr<std::unique_ptr<RtpTransportInterface>>,
76 CreateRtpTransport,
77 const RtcpParameters&,
78 PacketTransportInterface*,
79 PacketTransportInterface*,
80 RtpTransportControllerInterface*)
81 PROXY_METHOD4(RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>,
82 CreateSrtpTransport,
83 const RtcpParameters&,
84 PacketTransportInterface*,
85 PacketTransportInterface*,
86 RtpTransportControllerInterface*)
87 PROXY_CONSTMETHOD1(RtpCapabilities,
88 GetRtpSenderCapabilities,
89 cricket::MediaType)
90 PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>,
91 CreateRtpSender,
92 rtc::scoped_refptr<MediaStreamTrackInterface>,
93 RtpTransportInterface*)
94 PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>,
95 CreateRtpSender,
96 cricket::MediaType,
97 RtpTransportInterface*)
98 PROXY_CONSTMETHOD1(RtpCapabilities,
99 GetRtpReceiverCapabilities,
100 cricket::MediaType)
101 PROXY_METHOD2(RTCErrorOr<std::unique_ptr<OrtcRtpReceiverInterface>>,
102 CreateRtpReceiver,
103 cricket::MediaType,
104 RtpTransportInterface*)
105 PROXY_WORKER_METHOD3(RTCErrorOr<std::unique_ptr<UdpTransportInterface>>,
106 CreateUdpTransport,
107 int,
108 uint16_t,
109 uint16_t)
110 PROXY_METHOD1(rtc::scoped_refptr<AudioSourceInterface>,
111 CreateAudioSource,
112 const cricket::AudioOptions&)
113 PROXY_METHOD2(rtc::scoped_refptr<VideoTrackSourceInterface>,
114 CreateVideoSource,
115 std::unique_ptr<cricket::VideoCapturer>,
116 const MediaConstraintsInterface*)
117 PROXY_METHOD2(rtc::scoped_refptr<VideoTrackInterface>,
118 CreateVideoTrack,
119 const std::string&,
120 VideoTrackSourceInterface*)
121 PROXY_METHOD2(rtc::scoped_refptr<AudioTrackInterface>,
122 CreateAudioTrack,
123 const std::string&,
124 AudioSourceInterface*)
125 END_PROXY_MAP()
126
127 // static
128 RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>> OrtcFactory::Create(
129 rtc::Thread* network_thread,
130 rtc::Thread* signaling_thread,
131 rtc::NetworkManager* network_manager,
132 rtc::PacketSocketFactory* socket_factory,
133 AudioDeviceModule* adm,
134 std::unique_ptr<cricket::MediaEngineInterface> media_engine) {
135 // Hop to signaling thread if needed.
136 if (signaling_thread && !signaling_thread->IsCurrent()) {
137 return signaling_thread
138 ->Invoke<RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>>>(
139 RTC_FROM_HERE,
140 rtc::Bind(&OrtcFactoryInterface::Create, network_thread,
141 signaling_thread, network_manager, socket_factory, adm));
142 }
143 std::unique_ptr<OrtcFactory> new_factory(new OrtcFactory(
144 network_thread, signaling_thread, network_manager, socket_factory, adm));
145 RTCError err = new_factory->Initialize(std::move(media_engine));
146 if (!err.ok()) {
147 return err;
148 }
149 // Return a proxy so that any calls on the returned object (including
150 // destructor) happen on the signaling thread.
151 return OrtcFactoryProxy::Create(new_factory->signaling_thread(),
152 new_factory->network_thread(),
153 new_factory.release());
154 }
155
156 RTCErrorOr<std::unique_ptr<OrtcFactoryInterface>> OrtcFactoryInterface::Create(
157 rtc::Thread* network_thread,
158 rtc::Thread* signaling_thread,
159 rtc::NetworkManager* network_manager,
160 rtc::PacketSocketFactory* socket_factory,
161 AudioDeviceModule* adm) {
162 return OrtcFactory::Create(network_thread, signaling_thread, network_manager,
163 socket_factory, adm, nullptr);
164 }
165
166 OrtcFactory::OrtcFactory(rtc::Thread* network_thread,
167 rtc::Thread* signaling_thread,
168 rtc::NetworkManager* network_manager,
169 rtc::PacketSocketFactory* socket_factory,
170 AudioDeviceModule* adm)
171 : network_thread_(network_thread),
172 signaling_thread_(signaling_thread),
173 network_manager_(network_manager),
174 socket_factory_(socket_factory),
175 adm_(adm),
176 null_event_log_(RtcEventLog::CreateNull()),
177 audio_decoder_factory_(CreateBuiltinAudioDecoderFactory()) {
178 if (!rtc::CreateRandomString(kDefaultRtcpCnameLength, &default_cname_)) {
179 LOG(LS_ERROR) << "Failed to generate CNAME?";
180 RTC_NOTREACHED();
181 }
182 if (!network_thread_) {
183 owned_network_thread_ = rtc::Thread::CreateWithSocketServer();
184 owned_network_thread_->Start();
185 network_thread_ = owned_network_thread_.get();
186 }
187
188 // The worker thread is created internally because it's an implementation
189 // detail, and consumers of the API don't need to really know about it.
190 worker_thread_ = rtc::Thread::Create();
191 worker_thread_->Start();
192
193 if (signaling_thread_) {
194 RTC_DCHECK_RUN_ON(signaling_thread_);
195 } else {
196 signaling_thread_ = rtc::Thread::Current();
197 if (!signaling_thread_) {
198 // If this thread isn't already wrapped by an rtc::Thread, create a
199 // wrapper and own it in this class.
200 signaling_thread_ = rtc::ThreadManager::Instance()->WrapCurrentThread();
201 wraps_signaling_thread_ = true;
202 }
203 }
204 if (!network_manager_) {
205 owned_network_manager_.reset(new rtc::BasicNetworkManager());
206 network_manager_ = owned_network_manager_.get();
207 }
208 if (!socket_factory_) {
209 owned_socket_factory_.reset(
210 new rtc::BasicPacketSocketFactory(network_thread_));
211 socket_factory_ = owned_socket_factory_.get();
212 }
213 }
214
215 OrtcFactory::~OrtcFactory() {
216 RTC_DCHECK_RUN_ON(signaling_thread_);
217 if (wraps_signaling_thread_) {
218 rtc::ThreadManager::Instance()->UnwrapCurrentThread();
219 }
220 }
221
222 RTCErrorOr<std::unique_ptr<RtpTransportControllerInterface>>
223 OrtcFactory::CreateRtpTransportController() {
224 RTC_DCHECK_RUN_ON(signaling_thread_);
225 return RtpTransportControllerAdapter::CreateProxied(
226 cricket::MediaConfig(), channel_manager_.get(), null_event_log_.get(),
227 signaling_thread_, worker_thread_.get());
228 }
229
230 RTCErrorOr<std::unique_ptr<RtpTransportInterface>>
231 OrtcFactory::CreateRtpTransport(
232 const RtcpParameters& rtcp_parameters,
233 PacketTransportInterface* rtp,
234 PacketTransportInterface* rtcp,
235 RtpTransportControllerInterface* transport_controller) {
236 RTC_DCHECK_RUN_ON(signaling_thread_);
237 RtcpParameters copied_parameters = rtcp_parameters;
238 if (copied_parameters.cname.empty()) {
239 copied_parameters.cname = default_cname_;
240 }
241 if (transport_controller) {
242 return transport_controller->GetInternal()->CreateProxiedRtpTransport(
243 copied_parameters, rtp, rtcp);
244 } else {
245 // If |transport_controller| is null, create one automatically, which the
246 // returned RtpTransport will own.
247 auto controller_result = CreateRtpTransportController();
248 if (!controller_result.ok()) {
249 return controller_result.MoveError();
250 }
251 auto controller = controller_result.MoveValue();
252 auto transport_result =
253 controller->GetInternal()->CreateProxiedRtpTransport(copied_parameters,
254 rtp, rtcp);
255 // If RtpTransport was successfully created, transfer ownership of
256 // |rtp_transport_controller|. Otherwise it will go out of scope and be
257 // deleted automatically.
258 if (transport_result.ok()) {
259 transport_result.value()
260 ->GetInternal()
261 ->TakeOwnershipOfRtpTransportController(std::move(controller));
262 }
263 return transport_result;
264 }
265 }
266
267 RTCErrorOr<std::unique_ptr<SrtpTransportInterface>>
268 OrtcFactory::CreateSrtpTransport(
269 const RtcpParameters& rtcp_parameters,
270 PacketTransportInterface* rtp,
271 PacketTransportInterface* rtcp,
272 RtpTransportControllerInterface* transport_controller) {
273 RTC_DCHECK_RUN_ON(signaling_thread_);
274 RtcpParameters copied_parameters = rtcp_parameters;
275 if (copied_parameters.cname.empty()) {
276 copied_parameters.cname = default_cname_;
277 }
278 if (transport_controller) {
279 return transport_controller->GetInternal()->CreateProxiedSrtpTransport(
280 copied_parameters, rtp, rtcp);
281 } else {
282 // If |transport_controller| is null, create one automatically, which the
283 // returned SrtpTransport will own.
284 auto controller_result = CreateRtpTransportController();
285 if (!controller_result.ok()) {
286 return controller_result.MoveError();
287 }
288 auto controller = controller_result.MoveValue();
289 auto transport_result =
290 controller->GetInternal()->CreateProxiedSrtpTransport(copied_parameters,
291 rtp, rtcp);
292 // If SrtpTransport was successfully created, transfer ownership of
293 // |rtp_transport_controller|. Otherwise it will go out of scope and be
294 // deleted automatically.
295 if (transport_result.ok()) {
296 transport_result.value()
297 ->GetInternal()
298 ->TakeOwnershipOfRtpTransportController(std::move(controller));
299 }
300 return transport_result;
301 }
302 }
303
304 RtpCapabilities OrtcFactory::GetRtpSenderCapabilities(
305 cricket::MediaType kind) const {
306 RTC_DCHECK_RUN_ON(signaling_thread_);
307 switch (kind) {
308 case cricket::MEDIA_TYPE_AUDIO: {
309 cricket::AudioCodecs cricket_codecs;
310 cricket::RtpHeaderExtensions cricket_extensions;
311 channel_manager_->GetSupportedAudioSendCodecs(&cricket_codecs);
312 channel_manager_->GetSupportedAudioRtpHeaderExtensions(
313 &cricket_extensions);
314 return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions);
315 }
316 case cricket::MEDIA_TYPE_VIDEO: {
317 cricket::VideoCodecs cricket_codecs;
318 cricket::RtpHeaderExtensions cricket_extensions;
319 channel_manager_->GetSupportedVideoCodecs(&cricket_codecs);
320 channel_manager_->GetSupportedVideoRtpHeaderExtensions(
321 &cricket_extensions);
322 return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions);
323 }
324 case cricket::MEDIA_TYPE_DATA:
325 return RtpCapabilities();
326 }
327 }
328
329 RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>
330 OrtcFactory::CreateRtpSender(
331 rtc::scoped_refptr<MediaStreamTrackInterface> track,
332 RtpTransportInterface* transport) {
333 RTC_DCHECK_RUN_ON(signaling_thread_);
334 if (!track) {
335 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
336 "Cannot pass null track into CreateRtpSender.");
337 }
338 auto result =
339 CreateRtpSender(cricket::MediaTypeFromString(track->kind()), transport);
340 if (!result.ok()) {
341 return result;
342 }
343 auto err = result.value()->SetTrack(track);
344 if (!err.ok()) {
345 return err;
346 }
347 return result;
348 }
349
350 RTCErrorOr<std::unique_ptr<OrtcRtpSenderInterface>>
351 OrtcFactory::CreateRtpSender(cricket::MediaType kind,
352 RtpTransportInterface* transport) {
353 RTC_DCHECK_RUN_ON(signaling_thread_);
354 if (kind == cricket::MEDIA_TYPE_DATA) {
355 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
356 "Cannot create data RtpSender.");
357 }
358 if (!transport) {
359 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
360 "Cannot pass null transport into CreateRtpSender.");
361 }
362 return transport->GetInternal()
363 ->rtp_transport_controller()
364 ->CreateProxiedRtpSender(kind, transport);
365 }
366
367 RtpCapabilities OrtcFactory::GetRtpReceiverCapabilities(
368 cricket::MediaType kind) const {
369 RTC_DCHECK_RUN_ON(signaling_thread_);
370 switch (kind) {
371 case cricket::MEDIA_TYPE_AUDIO: {
372 cricket::AudioCodecs cricket_codecs;
373 cricket::RtpHeaderExtensions cricket_extensions;
374 channel_manager_->GetSupportedAudioReceiveCodecs(&cricket_codecs);
375 channel_manager_->GetSupportedAudioRtpHeaderExtensions(
376 &cricket_extensions);
377 return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions);
378 }
379 case cricket::MEDIA_TYPE_VIDEO: {
380 cricket::VideoCodecs cricket_codecs;
381 cricket::RtpHeaderExtensions cricket_extensions;
382 channel_manager_->GetSupportedVideoCodecs(&cricket_codecs);
383 channel_manager_->GetSupportedVideoRtpHeaderExtensions(
384 &cricket_extensions);
385 return ToRtpCapabilitiesWithAsserts(cricket_codecs, cricket_extensions);
386 }
387 case cricket::MEDIA_TYPE_DATA:
388 return RtpCapabilities();
389 }
390 }
391
392 RTCErrorOr<std::unique_ptr<OrtcRtpReceiverInterface>>
393 OrtcFactory::CreateRtpReceiver(cricket::MediaType kind,
394 RtpTransportInterface* transport) {
395 RTC_DCHECK_RUN_ON(signaling_thread_);
396 if (kind == cricket::MEDIA_TYPE_DATA) {
397 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
398 "Cannot create data RtpReceiver.");
399 }
400 if (!transport) {
401 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
402 "Cannot pass null transport into CreateRtpReceiver.");
403 }
404 return transport->GetInternal()
405 ->rtp_transport_controller()
406 ->CreateProxiedRtpReceiver(kind, transport);
407 }
408
409 // UdpTransport expects all methods to be called on one thread, which needs to
410 // be the network thread, since that's where its socket can safely be used. So
411 // return a proxy to the created UdpTransport.
412 BEGIN_OWNED_PROXY_MAP(UdpTransport)
413 PROXY_WORKER_THREAD_DESTRUCTOR()
414 PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetLocalAddress)
415 PROXY_WORKER_METHOD1(bool, SetRemoteAddress, const rtc::SocketAddress&)
416 PROXY_WORKER_CONSTMETHOD0(rtc::SocketAddress, GetRemoteAddress)
417 protected:
418 rtc::PacketTransportInternal* GetInternal() override {
419 return internal();
420 }
421 END_PROXY_MAP()
422
423 RTCErrorOr<std::unique_ptr<UdpTransportInterface>>
424 OrtcFactory::CreateUdpTransport(int family,
425 uint16_t min_port,
426 uint16_t max_port) {
427 RTC_DCHECK_RUN_ON(network_thread_);
428 if (family != AF_INET && family != AF_INET6) {
429 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
430 "Address family must be AF_INET or AF_INET6.");
431 }
432 if (min_port > max_port) {
433 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_RANGE,
434 "Port range invalid; minimum port must be less than "
435 "or equal to max port.");
436 }
437 std::unique_ptr<rtc::AsyncPacketSocket> socket(
438 socket_factory_->CreateUdpSocket(
439 rtc::SocketAddress(rtc::GetAnyIP(family), 0), min_port, max_port));
440 if (!socket) {
441 // Only log at warning level, because this method may be called with
442 // specific port ranges to determine if a port is available, expecting the
443 // possibility of an error.
444 LOG_AND_RETURN_ERROR_EX(RTCErrorType::RESOURCE_EXHAUSTED,
445 "Local socket allocation failure.", LS_WARNING);
446 }
447 LOG(LS_INFO) << "Created UDP socket with address "
448 << socket->GetLocalAddress().ToSensitiveString() << ".";
449 // Make a unique debug name (for logging/diagnostics only).
450 std::ostringstream oss;
451 static int udp_id = 0;
452 oss << "udp" << udp_id++;
453 return UdpTransportProxyWithInternal<cricket::UdpTransport>::Create(
454 signaling_thread_, network_thread_,
455 new cricket::UdpTransport(oss.str(), std::move(socket)));
456 }
457
458 rtc::scoped_refptr<AudioSourceInterface> OrtcFactory::CreateAudioSource(
459 const cricket::AudioOptions& options) {
460 RTC_DCHECK_RUN_ON(signaling_thread_);
461 return rtc::scoped_refptr<LocalAudioSource>(
462 LocalAudioSource::Create(&options));
463 }
464
465 rtc::scoped_refptr<VideoTrackSourceInterface> OrtcFactory::CreateVideoSource(
466 std::unique_ptr<cricket::VideoCapturer> capturer,
467 const MediaConstraintsInterface* constraints) {
468 RTC_DCHECK_RUN_ON(signaling_thread_);
469 rtc::scoped_refptr<VideoTrackSourceInterface> source(
470 VideoCapturerTrackSource::Create(
471 worker_thread_.get(), std::move(capturer), constraints, false));
472 return VideoTrackSourceProxy::Create(signaling_thread_, worker_thread_.get(),
473 source);
474 }
475
476 rtc::scoped_refptr<VideoTrackInterface> OrtcFactory::CreateVideoTrack(
477 const std::string& id,
478 VideoTrackSourceInterface* source) {
479 RTC_DCHECK_RUN_ON(signaling_thread_);
480 rtc::scoped_refptr<VideoTrackInterface> track(VideoTrack::Create(id, source));
481 return VideoTrackProxy::Create(signaling_thread_, worker_thread_.get(),
482 track);
483 }
484
485 rtc::scoped_refptr<AudioTrackInterface> OrtcFactory::CreateAudioTrack(
486 const std::string& id,
487 AudioSourceInterface* source) {
488 RTC_DCHECK_RUN_ON(signaling_thread_);
489 rtc::scoped_refptr<AudioTrackInterface> track(AudioTrack::Create(id, source));
490 return AudioTrackProxy::Create(signaling_thread_, track);
491 }
492
493 RTCError OrtcFactory::Initialize(
494 std::unique_ptr<cricket::MediaEngineInterface> media_engine) {
495 RTC_DCHECK_RUN_ON(signaling_thread_);
496 // TODO(deadbeef): Get rid of requirement to hop to worker thread here.
497 if (!media_engine) {
498 media_engine =
499 worker_thread_->Invoke<std::unique_ptr<cricket::MediaEngineInterface>>(
500 RTC_FROM_HERE, rtc::Bind(&OrtcFactory::CreateMediaEngine_w, this));
501 }
502
503 channel_manager_.reset(new cricket::ChannelManager(
504 std::move(media_engine), worker_thread_.get(), network_thread_));
505 channel_manager_->SetVideoRtxEnabled(true);
506 if (!channel_manager_->Init()) {
507 LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
508 "Failed to initialize ChannelManager.");
509 }
510 return RTCError::OK();
511 }
512
513 std::unique_ptr<cricket::MediaEngineInterface>
514 OrtcFactory::CreateMediaEngine_w() {
515 RTC_DCHECK_RUN_ON(worker_thread_.get());
516 // The null arguments are optional factories that could be passed into the
517 // OrtcFactory, but aren't yet.
518 //
519 // Note that |adm_| may be null, in which case the platform-specific default
520 // AudioDeviceModule will be used.
521 return std::unique_ptr<cricket::MediaEngineInterface>(
522 cricket::WebRtcMediaEngineFactory::Create(adm_, audio_decoder_factory_,
523 nullptr, nullptr, nullptr));
524 }
525
526 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698