blob: f62cd87bb17e52555ea3aec82c632ebacaaeb25e [file] [log] [blame]
Zhi Huange818b6e2018-02-22 15:26:27 -08001/*
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
Steve Anton10542f22019-01-11 09:11:00 -080011#include "pc/jsep_transport_controller.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080012
Zhi Huange818b6e2018-02-22 15:26:27 -080013#include <memory>
14#include <utility>
15
Steve Anton64b626b2019-01-28 17:25:26 -080016#include "absl/algorithm/container.h"
Qingsi Wang25ec8882019-11-15 12:33:05 -080017#include "api/ice_transport_factory.h"
Niels Möller65f17ca2019-09-12 13:59:36 +020018#include "api/transport/datagram_transport_interface.h"
19#include "api/transport/media/media_transport_interface.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080020#include "p2p/base/ice_transport_internal.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080021#include "p2p/base/port.h"
Bjorn A Mellem364b2672019-08-20 16:58:03 -070022#include "pc/datagram_rtp_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080023#include "pc/srtp_filter.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080024#include "rtc_base/bind.h"
25#include "rtc_base/checks.h"
Zhi Huange818b6e2018-02-22 15:26:27 -080026#include "rtc_base/thread.h"
27
28using webrtc::SdpType;
29
30namespace {
31
Zhi Huange818b6e2018-02-22 15:26:27 -080032webrtc::RTCError VerifyCandidate(const cricket::Candidate& cand) {
33 // No address zero.
34 if (cand.address().IsNil() || cand.address().IsAnyIP()) {
35 return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
36 "candidate has address of zero");
37 }
38
39 // Disallow all ports below 1024, except for 80 and 443 on public addresses.
40 int port = cand.address().port();
41 if (cand.protocol() == cricket::TCP_PROTOCOL_NAME &&
42 (cand.tcptype() == cricket::TCPTYPE_ACTIVE_STR || port == 0)) {
43 // Expected for active-only candidates per
44 // http://tools.ietf.org/html/rfc6544#section-4.5 so no error.
45 // Libjingle clients emit port 0, in "active" mode.
46 return webrtc::RTCError::OK();
47 }
48 if (port < 1024) {
49 if ((port != 80) && (port != 443)) {
50 return webrtc::RTCError(
51 webrtc::RTCErrorType::INVALID_PARAMETER,
52 "candidate has port below 1024, but not 80 or 443");
53 }
54
55 if (cand.address().IsPrivateIP()) {
56 return webrtc::RTCError(
57 webrtc::RTCErrorType::INVALID_PARAMETER,
58 "candidate has port of 80 or 443 with private IP address");
59 }
60 }
61
62 return webrtc::RTCError::OK();
63}
64
65webrtc::RTCError VerifyCandidates(const cricket::Candidates& candidates) {
66 for (const cricket::Candidate& candidate : candidates) {
67 webrtc::RTCError error = VerifyCandidate(candidate);
68 if (!error.ok()) {
69 return error;
70 }
71 }
72 return webrtc::RTCError::OK();
73}
74
75} // namespace
76
77namespace webrtc {
78
79JsepTransportController::JsepTransportController(
80 rtc::Thread* signaling_thread,
81 rtc::Thread* network_thread,
82 cricket::PortAllocator* port_allocator,
Zach Steine20867f2018-08-02 13:20:15 -070083 AsyncResolverFactory* async_resolver_factory,
Zhi Huange818b6e2018-02-22 15:26:27 -080084 Config config)
85 : signaling_thread_(signaling_thread),
86 network_thread_(network_thread),
87 port_allocator_(port_allocator),
Zach Steine20867f2018-08-02 13:20:15 -070088 async_resolver_factory_(async_resolver_factory),
Zhi Huang365381f2018-04-13 16:44:34 -070089 config_(config) {
90 // The |transport_observer| is assumed to be non-null.
91 RTC_DCHECK(config_.transport_observer);
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020092 RTC_DCHECK(config_.rtcp_handler);
Qingsi Wang25ec8882019-11-15 12:33:05 -080093 RTC_DCHECK(config_.ice_transport_factory);
Zhi Huang365381f2018-04-13 16:44:34 -070094}
Zhi Huange818b6e2018-02-22 15:26:27 -080095
96JsepTransportController::~JsepTransportController() {
97 // Channel destructors may try to send packets, so this needs to happen on
98 // the network thread.
99 network_thread_->Invoke<void>(
100 RTC_FROM_HERE,
101 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
102}
103
104RTCError JsepTransportController::SetLocalDescription(
105 SdpType type,
106 const cricket::SessionDescription* description) {
107 if (!network_thread_->IsCurrent()) {
108 return network_thread_->Invoke<RTCError>(
109 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
110 }
111
112 if (!initial_offerer_.has_value()) {
113 initial_offerer_.emplace(type == SdpType::kOffer);
114 if (*initial_offerer_) {
115 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
116 } else {
117 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
118 }
119 }
120 return ApplyDescription_n(/*local=*/true, type, description);
121}
122
123RTCError JsepTransportController::SetRemoteDescription(
124 SdpType type,
125 const cricket::SessionDescription* description) {
126 if (!network_thread_->IsCurrent()) {
127 return network_thread_->Invoke<RTCError>(
128 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
129 }
130
131 return ApplyDescription_n(/*local=*/false, type, description);
132}
133
134RtpTransportInternal* JsepTransportController::GetRtpTransport(
135 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700136 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800137 if (!jsep_transport) {
138 return nullptr;
139 }
140 return jsep_transport->rtp_transport();
141}
142
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700143MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700144 const std::string& mid) const {
145 auto jsep_transport = GetJsepTransportForMid(mid);
146 if (!jsep_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700147 return MediaTransportConfig();
148 }
149
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700150 DatagramTransportInterface* datagram_transport = nullptr;
151 if (config_.use_datagram_transport) {
152 datagram_transport = jsep_transport->datagram_transport();
153 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700154
Bjorn A Mellem7a9a0922019-11-26 09:19:40 -0800155 if (datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700156 return MediaTransportConfig(
157 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
158 } else {
159 return MediaTransportConfig();
160 }
161}
162
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700163DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700164 const std::string& mid) const {
165 auto jsep_transport = GetJsepTransportForMid(mid);
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700166 if (!jsep_transport) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700167 return nullptr;
168 }
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700169 return jsep_transport->data_channel_transport();
Anton Sukhanov7940da02018-10-10 10:34:49 -0700170}
171
Zhi Huange818b6e2018-02-22 15:26:27 -0800172cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100173 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700174 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800175 if (!jsep_transport) {
176 return nullptr;
177 }
178 return jsep_transport->rtp_dtls_transport();
179}
180
Harald Alvestrandad88c882018-11-28 16:47:46 +0100181const cricket::DtlsTransportInternal*
182JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700183 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800184 if (!jsep_transport) {
185 return nullptr;
186 }
187 return jsep_transport->rtcp_dtls_transport();
188}
189
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100190rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100191JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
192 auto jsep_transport = GetJsepTransportForMid(mid);
193 if (!jsep_transport) {
194 return nullptr;
195 }
196 return jsep_transport->RtpDtlsTransport();
197}
198
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700199rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
200 const std::string& mid) const {
201 auto jsep_transport = GetJsepTransportForMid(mid);
202 if (!jsep_transport) {
203 return nullptr;
204 }
205 return jsep_transport->SctpTransport();
206}
207
Zhi Huange818b6e2018-02-22 15:26:27 -0800208void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
209 if (!network_thread_->IsCurrent()) {
210 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
211 return;
212 }
213
214 ice_config_ = config;
215 for (auto& dtls : GetDtlsTransports()) {
216 dtls->ice_transport()->SetIceConfig(ice_config_);
217 }
218}
219
220void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700221 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800222 kv.second->SetNeedsIceRestartFlag();
223 }
224}
225
226bool JsepTransportController::NeedsIceRestart(
227 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700228 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700229 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800230 if (!transport) {
231 return false;
232 }
233 return transport->needs_ice_restart();
234}
235
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200236absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700237 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800238 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200239 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700240 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800241 }
242
Zhi Huang365381f2018-04-13 16:44:34 -0700243 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800244 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200245 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800246 }
247 return t->GetDtlsRole();
248}
249
250bool JsepTransportController::SetLocalCertificate(
251 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
252 if (!network_thread_->IsCurrent()) {
253 return network_thread_->Invoke<bool>(
254 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
255 }
256
257 // Can't change a certificate, or set a null certificate.
258 if (certificate_ || !certificate) {
259 return false;
260 }
261 certificate_ = certificate;
262
263 // Set certificate for JsepTransport, which verifies it matches the
264 // fingerprint in SDP, and DTLS transport.
265 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700266 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800267 kv.second->SetLocalCertificate(certificate_);
268 }
269 for (auto& dtls : GetDtlsTransports()) {
270 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
271 RTC_DCHECK(set_cert_success);
272 }
273 return true;
274}
275
276rtc::scoped_refptr<rtc::RTCCertificate>
277JsepTransportController::GetLocalCertificate(
278 const std::string& transport_name) const {
279 if (!network_thread_->IsCurrent()) {
280 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
281 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
282 }
283
Zhi Huang365381f2018-04-13 16:44:34 -0700284 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800285 if (!t) {
286 return nullptr;
287 }
288 return t->GetLocalCertificate();
289}
290
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800291std::unique_ptr<rtc::SSLCertChain>
292JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800293 const std::string& transport_name) const {
294 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800295 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
296 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800297 }
298
Zhi Huange830e682018-03-30 10:48:35 -0700299 // Get the certificate from the RTP transport's DTLS handshake. Should be
300 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800301 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700302 auto jsep_transport = GetJsepTransportByName(transport_name);
303 if (!jsep_transport) {
304 return nullptr;
305 }
306 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800307 if (!dtls) {
308 return nullptr;
309 }
310
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800311 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800312}
313
314void JsepTransportController::MaybeStartGathering() {
315 if (!network_thread_->IsCurrent()) {
316 network_thread_->Invoke<void>(RTC_FROM_HERE,
317 [&] { MaybeStartGathering(); });
318 return;
319 }
320
321 for (auto& dtls : GetDtlsTransports()) {
322 dtls->ice_transport()->MaybeStartGathering();
323 }
324}
325
326RTCError JsepTransportController::AddRemoteCandidates(
327 const std::string& transport_name,
328 const cricket::Candidates& candidates) {
329 if (!network_thread_->IsCurrent()) {
330 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
331 return AddRemoteCandidates(transport_name, candidates);
332 });
333 }
334
335 // Verify each candidate before passing down to the transport layer.
336 RTCError error = VerifyCandidates(candidates);
337 if (!error.ok()) {
338 return error;
339 }
Zhi Huange830e682018-03-30 10:48:35 -0700340 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800341 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700342 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
343 "doesn't exist. Ignore it.";
344 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800345 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800346 return jsep_transport->AddRemoteCandidates(candidates);
347}
348
349RTCError JsepTransportController::RemoveRemoteCandidates(
350 const cricket::Candidates& candidates) {
351 if (!network_thread_->IsCurrent()) {
352 return network_thread_->Invoke<RTCError>(
353 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
354 }
355
356 // Verify each candidate before passing down to the transport layer.
357 RTCError error = VerifyCandidates(candidates);
358 if (!error.ok()) {
359 return error;
360 }
361
362 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
363 for (const cricket::Candidate& cand : candidates) {
364 if (!cand.transport_name().empty()) {
365 candidates_by_transport_name[cand.transport_name()].push_back(cand);
366 } else {
367 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
368 "transport name set: "
Qingsi Wang20232a92019-09-06 12:51:17 -0700369 << cand.ToSensitiveString();
Zhi Huange818b6e2018-02-22 15:26:27 -0800370 }
371 }
372
373 for (const auto& kv : candidates_by_transport_name) {
374 const std::string& transport_name = kv.first;
375 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700376 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700377 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800378 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700379 RTC_LOG(LS_WARNING)
380 << "Not removing candidate because the JsepTransport doesn't exist.";
381 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800382 }
383 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100384 cricket::DtlsTransportInternal* dtls =
385 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
386 ? jsep_transport->rtp_dtls_transport()
387 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800388 if (dtls) {
389 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
390 }
391 }
392 }
393 return RTCError::OK();
394}
395
396bool JsepTransportController::GetStats(const std::string& transport_name,
397 cricket::TransportStats* stats) {
398 if (!network_thread_->IsCurrent()) {
399 return network_thread_->Invoke<bool>(
400 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
401 }
402
Zhi Huang365381f2018-04-13 16:44:34 -0700403 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800404 if (!transport) {
405 return false;
406 }
407 return transport->GetStats(stats);
408}
409
Zhi Huangb57e1692018-06-12 11:41:11 -0700410void JsepTransportController::SetActiveResetSrtpParams(
411 bool active_reset_srtp_params) {
412 if (!network_thread_->IsCurrent()) {
413 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
414 SetActiveResetSrtpParams(active_reset_srtp_params);
415 });
416 return;
417 }
418
419 RTC_LOG(INFO)
420 << "Updating the active_reset_srtp_params for JsepTransportController: "
421 << active_reset_srtp_params;
422 config_.active_reset_srtp_params = active_reset_srtp_params;
423 for (auto& kv : jsep_transports_by_name_) {
424 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
425 }
426}
427
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800428void JsepTransportController::SetMediaTransportSettings(
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700429 bool use_datagram_transport,
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700430 bool use_datagram_transport_for_data_channels,
431 bool use_datagram_transport_for_data_channels_receive_only) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700432 config_.use_datagram_transport = use_datagram_transport;
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700433 config_.use_datagram_transport_for_data_channels =
434 use_datagram_transport_for_data_channels;
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700435 config_.use_datagram_transport_for_data_channels_receive_only =
436 use_datagram_transport_for_data_channels_receive_only;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700437}
438
Eldar Rello353a7182019-11-25 18:49:44 +0200439void JsepTransportController::RollbackTransportForMids(
440 const std::vector<std::string>& mids) {
Eldar Rello5ab79e62019-10-09 18:29:44 +0300441 if (!network_thread_->IsCurrent()) {
442 network_thread_->Invoke<void>(RTC_FROM_HERE,
Eldar Rello353a7182019-11-25 18:49:44 +0200443 [=] { RollbackTransportForMids(mids); });
Eldar Rello5ab79e62019-10-09 18:29:44 +0300444 return;
445 }
Eldar Rello353a7182019-11-25 18:49:44 +0200446 for (auto&& mid : mids) {
447 RemoveTransportForMid(mid);
448 }
449 for (auto&& mid : mids) {
450 MaybeDestroyJsepTransport(mid);
451 }
Eldar Rello5ab79e62019-10-09 18:29:44 +0300452}
453
Qingsi Wang25ec8882019-11-15 12:33:05 -0800454rtc::scoped_refptr<webrtc::IceTransportInterface>
455JsepTransportController::CreateIceTransport(const std::string& transport_name,
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800456 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800457 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
458 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
459
Qingsi Wang25ec8882019-11-15 12:33:05 -0800460 IceTransportInit init;
461 init.set_port_allocator(port_allocator_);
462 init.set_async_resolver_factory(async_resolver_factory_);
463 init.set_event_log(config_.event_log);
464 return config_.ice_transport_factory->CreateIceTransport(
465 transport_name, component, std::move(init));
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800466}
467
468std::unique_ptr<cricket::DtlsTransportInternal>
469JsepTransportController::CreateDtlsTransport(
Anton Sukhanovac6c0962019-07-10 15:44:56 -0700470 const cricket::ContentInfo& content_info,
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700471 cricket::IceTransportInternal* ice,
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700472 DatagramTransportInterface* datagram_transport) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800473 RTC_DCHECK(network_thread_->IsCurrent());
474
475 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700476
477 if (datagram_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700478 RTC_DCHECK(config_.use_datagram_transport ||
479 config_.use_datagram_transport_for_data_channels);
Qingsi Wang25ec8882019-11-15 12:33:05 -0800480 } else if (config_.dtls_transport_factory) {
481 dtls = config_.dtls_transport_factory->CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700482 ice, config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800483 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200484 dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
485 config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800486 }
487
488 RTC_DCHECK(dtls);
489 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800490 dtls->ice_transport()->SetIceRole(ice_role_);
491 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
492 dtls->ice_transport()->SetIceConfig(ice_config_);
493 if (certificate_) {
494 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
495 RTC_DCHECK(set_cert_success);
496 }
497
498 // Connect to signals offered by the DTLS and ICE transport.
499 dtls->SignalWritableState.connect(
500 this, &JsepTransportController::OnTransportWritableState_n);
501 dtls->SignalReceivingState.connect(
502 this, &JsepTransportController::OnTransportReceivingState_n);
503 dtls->SignalDtlsHandshakeError.connect(
504 this, &JsepTransportController::OnDtlsHandshakeError);
505 dtls->ice_transport()->SignalGatheringState.connect(
506 this, &JsepTransportController::OnTransportGatheringState_n);
507 dtls->ice_transport()->SignalCandidateGathered.connect(
508 this, &JsepTransportController::OnTransportCandidateGathered_n);
Eldar Relloda13ea22019-06-01 12:23:43 +0300509 dtls->ice_transport()->SignalCandidateError.connect(
510 this, &JsepTransportController::OnTransportCandidateError_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800511 dtls->ice_transport()->SignalCandidatesRemoved.connect(
512 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
513 dtls->ice_transport()->SignalRoleConflict.connect(
514 this, &JsepTransportController::OnTransportRoleConflict_n);
515 dtls->ice_transport()->SignalStateChanged.connect(
516 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100517 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
518 this, &JsepTransportController::OnTransportStateChanged_n);
Alex Drake00c7ecf2019-08-06 10:54:47 -0700519 dtls->ice_transport()->SignalCandidatePairChanged.connect(
520 this, &JsepTransportController::OnTransportCandidatePairChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800521 return dtls;
522}
523
524std::unique_ptr<webrtc::RtpTransport>
525JsepTransportController::CreateUnencryptedRtpTransport(
526 const std::string& transport_name,
527 rtc::PacketTransportInternal* rtp_packet_transport,
528 rtc::PacketTransportInternal* rtcp_packet_transport) {
529 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700530 auto unencrypted_rtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200531 std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700532 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
533 if (rtcp_packet_transport) {
534 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
535 }
536 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800537}
538
539std::unique_ptr<webrtc::SrtpTransport>
540JsepTransportController::CreateSdesTransport(
541 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700542 cricket::DtlsTransportInternal* rtp_dtls_transport,
543 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800544 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800545 auto srtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200546 std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700547 RTC_DCHECK(rtp_dtls_transport);
548 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
549 if (rtcp_dtls_transport) {
550 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800551 }
552 if (config_.enable_external_auth) {
553 srtp_transport->EnableExternalAuth();
554 }
555 return srtp_transport;
556}
557
558std::unique_ptr<webrtc::DtlsSrtpTransport>
559JsepTransportController::CreateDtlsSrtpTransport(
560 const std::string& transport_name,
561 cricket::DtlsTransportInternal* rtp_dtls_transport,
562 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
563 RTC_DCHECK(network_thread_->IsCurrent());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200564 auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700565 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700566 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700567 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700568 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000569
Zhi Huange818b6e2018-02-22 15:26:27 -0800570 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
571 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700572 dtls_srtp_transport->SetActiveResetSrtpParams(
573 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200574 dtls_srtp_transport->SignalDtlsStateChange.connect(
575 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800576 return dtls_srtp_transport;
577}
578
579std::vector<cricket::DtlsTransportInternal*>
580JsepTransportController::GetDtlsTransports() {
581 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700582 for (auto it = jsep_transports_by_name_.begin();
583 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800584 auto jsep_transport = it->second.get();
585 RTC_DCHECK(jsep_transport);
586 if (jsep_transport->rtp_dtls_transport()) {
587 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
588 }
589
590 if (jsep_transport->rtcp_dtls_transport()) {
591 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
592 }
593 }
594 return dtls_transports;
595}
596
Zhi Huange818b6e2018-02-22 15:26:27 -0800597RTCError JsepTransportController::ApplyDescription_n(
598 bool local,
599 SdpType type,
600 const cricket::SessionDescription* description) {
601 RTC_DCHECK(network_thread_->IsCurrent());
602 RTC_DCHECK(description);
603
604 if (local) {
605 local_desc_ = description;
606 } else {
607 remote_desc_ = description;
608 }
609
Zhi Huange830e682018-03-30 10:48:35 -0700610 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700611 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700612 if (!error.ok()) {
613 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800614 }
615
616 std::vector<int> merged_encrypted_extension_ids;
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700617 absl::optional<std::string> bundle_media_alt_protocol;
618 absl::optional<std::string> bundle_data_alt_protocol;
Zhi Huange818b6e2018-02-22 15:26:27 -0800619 if (bundle_group_) {
620 merged_encrypted_extension_ids =
621 MergeEncryptedHeaderExtensionIdsForBundle(description);
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700622 error = GetAltProtocolsForBundle(description, &bundle_media_alt_protocol,
623 &bundle_data_alt_protocol);
624 if (!error.ok()) {
625 return error;
626 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800627 }
628
629 for (const cricket::ContentInfo& content_info : description->contents()) {
630 // Don't create transports for rejected m-lines and bundled m-lines."
631 if (content_info.rejected ||
632 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
633 continue;
634 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800635 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700636 if (!error.ok()) {
637 return error;
638 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800639 }
640
641 RTC_DCHECK(description->contents().size() ==
642 description->transport_infos().size());
643 for (size_t i = 0; i < description->contents().size(); ++i) {
644 const cricket::ContentInfo& content_info = description->contents()[i];
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700645 const cricket::MediaContentDescription* media_description =
646 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800647 const cricket::TransportInfo& transport_info =
648 description->transport_infos()[i];
649 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700650 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800651 continue;
652 }
653
654 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700655 if (!HandleBundledContent(content_info)) {
656 return RTCError(RTCErrorType::INVALID_PARAMETER,
657 "Failed to process the bundled m= section.");
658 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800659 continue;
660 }
661
Zhi Huange830e682018-03-30 10:48:35 -0700662 error = ValidateContent(content_info);
663 if (!error.ok()) {
664 return error;
665 }
666
Zhi Huange818b6e2018-02-22 15:26:27 -0800667 std::vector<int> extension_ids;
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700668 absl::optional<std::string> media_alt_protocol;
669 absl::optional<std::string> data_alt_protocol;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700670 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800671 extension_ids = merged_encrypted_extension_ids;
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700672 media_alt_protocol = bundle_media_alt_protocol;
673 data_alt_protocol = bundle_data_alt_protocol;
Zhi Huange818b6e2018-02-22 15:26:27 -0800674 } else {
675 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700676 switch (media_description->type()) {
677 case cricket::MEDIA_TYPE_AUDIO:
678 case cricket::MEDIA_TYPE_VIDEO:
679 media_alt_protocol = media_description->alt_protocol();
680 break;
681 case cricket::MEDIA_TYPE_DATA:
682 data_alt_protocol = media_description->alt_protocol();
683 break;
684 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800685 }
686
Zhi Huange830e682018-03-30 10:48:35 -0700687 int rtp_abs_sendtime_extn_id =
688 GetRtpAbsSendTimeHeaderExtensionId(content_info);
689
Zhi Huang365381f2018-04-13 16:44:34 -0700690 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700691 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800692 RTC_DCHECK(transport);
693
694 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
695
Zhi Huange818b6e2018-02-22 15:26:27 -0800696 cricket::JsepTransportDescription jsep_description =
697 CreateJsepTransportDescription(content_info, transport_info,
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700698 extension_ids, rtp_abs_sendtime_extn_id,
699 media_alt_protocol, data_alt_protocol);
Zhi Huange818b6e2018-02-22 15:26:27 -0800700 if (local) {
701 error =
702 transport->SetLocalJsepTransportDescription(jsep_description, type);
703 } else {
704 error =
705 transport->SetRemoteJsepTransportDescription(jsep_description, type);
706 }
707
708 if (!error.ok()) {
709 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
710 "Failed to apply the description for " +
711 content_info.name + ": " + error.message());
712 }
713 }
714 return RTCError::OK();
715}
716
Zhi Huangd2248f82018-04-10 14:41:03 -0700717RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
718 bool local,
719 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700720 const cricket::SessionDescription* description) {
721 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700722 const cricket::ContentGroup* new_bundle_group =
723 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
724
725 // The BUNDLE group containing a MID that no m= section has is invalid.
726 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100727 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700728 if (!description->GetContentByName(content_name)) {
729 return RTCError(RTCErrorType::INVALID_PARAMETER,
730 "The BUNDLE group contains MID:" + content_name +
731 " matching no m= section.");
732 }
733 }
734 }
735
736 if (type == SdpType::kAnswer) {
737 const cricket::ContentGroup* offered_bundle_group =
738 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
739 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
740
741 if (new_bundle_group) {
742 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100743 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700744 if (!offered_bundle_group ||
745 !offered_bundle_group->HasContentName(content_name)) {
746 return RTCError(RTCErrorType::INVALID_PARAMETER,
747 "The BUNDLE group in answer contains a MID that was "
748 "not in the offered group.");
749 }
750 }
751 }
752
753 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100754 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700755 // An answer that removes m= sections from pre-negotiated BUNDLE group
756 // without rejecting it, is invalid.
757 if (!new_bundle_group ||
758 !new_bundle_group->HasContentName(content_name)) {
759 auto* content_info = description->GetContentByName(content_name);
760 if (!content_info || !content_info->rejected) {
761 return RTCError(RTCErrorType::INVALID_PARAMETER,
762 "Answer cannot remove m= section " + content_name +
763 " from already-established BUNDLE group.");
764 }
765 }
766 }
767 }
768 }
769
770 if (config_.bundle_policy ==
771 PeerConnectionInterface::kBundlePolicyMaxBundle &&
772 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
773 return RTCError(RTCErrorType::INVALID_PARAMETER,
774 "max-bundle is used but no bundle group found.");
775 }
776
777 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700778 bundle_group_ = *new_bundle_group;
779 }
Zhi Huange830e682018-03-30 10:48:35 -0700780
781 if (!bundled_mid()) {
782 return RTCError::OK();
783 }
784
785 auto bundled_content = description->GetContentByName(*bundled_mid());
786 if (!bundled_content) {
787 return RTCError(
788 RTCErrorType::INVALID_PARAMETER,
789 "An m= section associated with the BUNDLE-tag doesn't exist.");
790 }
791
792 // If the |bundled_content| is rejected, other contents in the bundle group
793 // should be rejected.
794 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100795 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700796 auto other_content = description->GetContentByName(content_name);
797 if (!other_content->rejected) {
798 return RTCError(
799 RTCErrorType::INVALID_PARAMETER,
800 "The m= section:" + content_name + " should be rejected.");
801 }
802 }
803 }
804
805 return RTCError::OK();
806}
807
808RTCError JsepTransportController::ValidateContent(
809 const cricket::ContentInfo& content_info) {
810 if (config_.rtcp_mux_policy ==
811 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
812 content_info.type == cricket::MediaProtocolType::kRtp &&
813 !content_info.media_description()->rtcp_mux()) {
814 return RTCError(RTCErrorType::INVALID_PARAMETER,
815 "The m= section:" + content_info.name +
816 " is invalid. RTCP-MUX is not "
817 "enabled when it is required.");
818 }
819 return RTCError::OK();
820}
821
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700822void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700823 const cricket::ContentInfo& content_info,
824 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800825 // If the content is rejected, let the
826 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700827 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700828 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700829 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100830 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700831 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700832 }
833 bundle_group_.reset();
834 } else if (IsBundled(content_info.name)) {
835 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800836 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700837 // Reset the bundle group if nothing left.
838 if (!bundle_group_->FirstContentName()) {
839 bundle_group_.reset();
840 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800841 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700842 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800843}
844
Zhi Huang365381f2018-04-13 16:44:34 -0700845bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800846 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700847 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
848 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800849 // If the content is bundled, let the
850 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700851 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700852 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800853 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
854 // because it means that we first create media transport and start
855 // connecting it, and then we destroy it. We will need to address it before
856 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700857 MaybeDestroyJsepTransport(content_info.name);
858 return true;
859 }
860 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800861}
862
Zhi Huang365381f2018-04-13 16:44:34 -0700863bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700864 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700865 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700866 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700867 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700868 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700869 }
870
871 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700872 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100873 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700874 jsep_transport->data_channel_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700875}
876
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700877void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Bjorn A Mellem7a9a0922019-11-26 09:19:40 -0800878 bool ret = config_.transport_observer->OnTransportChanged(mid, nullptr,
879 nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700880 // Calling OnTransportChanged with nullptr should always succeed, since it is
881 // only expected to fail when adding media to a transport (not removing).
882 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700883 mid_to_transport_.erase(mid);
884}
885
Zhi Huange818b6e2018-02-22 15:26:27 -0800886cricket::JsepTransportDescription
887JsepTransportController::CreateJsepTransportDescription(
Harald Alvestrand1716d392019-06-03 20:35:45 +0200888 const cricket::ContentInfo& content_info,
889 const cricket::TransportInfo& transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700890 const std::vector<int>& encrypted_extension_ids,
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700891 int rtp_abs_sendtime_extn_id,
892 absl::optional<std::string> media_alt_protocol,
893 absl::optional<std::string> data_alt_protocol) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800894 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200895 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800896 RTC_DCHECK(content_desc);
897 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
898 ? true
899 : content_desc->rtcp_mux();
900
901 return cricket::JsepTransportDescription(
902 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700903 rtp_abs_sendtime_extn_id, transport_info.description, media_alt_protocol,
904 data_alt_protocol);
Zhi Huange818b6e2018-02-22 15:26:27 -0800905}
906
907bool JsepTransportController::ShouldUpdateBundleGroup(
908 SdpType type,
909 const cricket::SessionDescription* description) {
910 if (config_.bundle_policy ==
911 PeerConnectionInterface::kBundlePolicyMaxBundle) {
912 return true;
913 }
914
915 if (type != SdpType::kAnswer) {
916 return false;
917 }
918
919 RTC_DCHECK(local_desc_ && remote_desc_);
920 const cricket::ContentGroup* local_bundle =
921 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
922 const cricket::ContentGroup* remote_bundle =
923 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
924 return local_bundle && remote_bundle;
925}
926
927std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
928 const cricket::ContentInfo& content_info) {
929 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200930 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800931
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700932 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800933 return std::vector<int>();
934 }
935
936 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100937 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800938 if (!extension.encrypt) {
939 continue;
940 }
Steve Anton64b626b2019-01-28 17:25:26 -0800941 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800942 encrypted_header_extension_ids.push_back(extension.id);
943 }
944 }
945 return encrypted_header_extension_ids;
946}
947
948std::vector<int>
949JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
950 const cricket::SessionDescription* description) {
951 RTC_DCHECK(description);
952 RTC_DCHECK(bundle_group_);
953
954 std::vector<int> merged_ids;
955 // Union the encrypted header IDs in the group when bundle is enabled.
956 for (const cricket::ContentInfo& content_info : description->contents()) {
957 if (bundle_group_->HasContentName(content_info.name)) {
958 std::vector<int> extension_ids =
959 GetEncryptedHeaderExtensionIds(content_info);
960 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -0800961 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800962 merged_ids.push_back(id);
963 }
964 }
965 }
966 }
967 return merged_ids;
968}
969
Bjorn A Mellem8e1343a2019-09-30 15:12:47 -0700970RTCError JsepTransportController::GetAltProtocolsForBundle(
971 const cricket::SessionDescription* description,
972 absl::optional<std::string>* media_alt_protocol,
973 absl::optional<std::string>* data_alt_protocol) {
974 RTC_DCHECK(description);
975 RTC_DCHECK(bundle_group_);
976 RTC_DCHECK(media_alt_protocol);
977 RTC_DCHECK(data_alt_protocol);
978
979 bool found_media = false;
980 bool found_data = false;
981 for (const cricket::ContentInfo& content : description->contents()) {
982 if (bundle_group_->HasContentName(content.name)) {
983 const cricket::MediaContentDescription* media_description =
984 content.media_description();
985 switch (media_description->type()) {
986 case cricket::MEDIA_TYPE_AUDIO:
987 case cricket::MEDIA_TYPE_VIDEO:
988 if (found_media &&
989 *media_alt_protocol != media_description->alt_protocol()) {
990 return RTCError(RTCErrorType::INVALID_PARAMETER,
991 "The BUNDLE group contains conflicting "
992 "alt-protocols for media ('" +
993 media_alt_protocol->value_or("") + "' and '" +
994 media_description->alt_protocol().value_or("") +
995 "')");
996 }
997 found_media = true;
998 *media_alt_protocol = media_description->alt_protocol();
999 break;
1000 case cricket::MEDIA_TYPE_DATA:
1001 if (found_data &&
1002 *data_alt_protocol != media_description->alt_protocol()) {
1003 return RTCError(RTCErrorType::INVALID_PARAMETER,
1004 "The BUNDLE group contains conflicting "
1005 "alt-protocols for data ('" +
1006 data_alt_protocol->value_or("") + "' and '" +
1007 media_description->alt_protocol().value_or("") +
1008 "')");
1009 }
1010 found_data = true;
1011 *data_alt_protocol = media_description->alt_protocol();
1012 break;
1013 }
1014 }
1015 }
1016 return RTCError::OK();
1017}
1018
Zhi Huange830e682018-03-30 10:48:35 -07001019int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -08001020 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -07001021 if (!config_.enable_external_auth) {
1022 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -08001023 }
1024
1025 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001026 content_info.media_description();
Zhi Huange830e682018-03-30 10:48:35 -07001027
1028 const webrtc::RtpExtension* send_time_extension =
1029 webrtc::RtpExtension::FindHeaderExtensionByUri(
1030 content_desc->rtp_header_extensions(),
1031 webrtc::RtpExtension::kAbsSendTimeUri);
1032 return send_time_extension ? send_time_extension->id : -1;
1033}
1034
Zhi Huang365381f2018-04-13 16:44:34 -07001035const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -07001036 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -07001037 auto it = mid_to_transport_.find(mid);
1038 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -07001039}
1040
Zhi Huang365381f2018-04-13 16:44:34 -07001041cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -07001042 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001043 auto it = mid_to_transport_.find(mid);
1044 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -07001045}
1046
Zhi Huang365381f2018-04-13 16:44:34 -07001047const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001048 const std::string& transport_name) const {
1049 auto it = jsep_transports_by_name_.find(transport_name);
1050 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1051}
1052
Zhi Huang365381f2018-04-13 16:44:34 -07001053cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001054 const std::string& transport_name) {
1055 auto it = jsep_transports_by_name_.find(transport_name);
1056 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1057}
1058
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001059// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
1060// transports setup.
1061std::unique_ptr<webrtc::DatagramTransportInterface>
1062JsepTransportController::MaybeCreateDatagramTransport(
1063 const cricket::ContentInfo& content_info,
1064 const cricket::SessionDescription& description,
1065 bool local) {
1066 if (config_.media_transport_factory == nullptr) {
1067 return nullptr;
1068 }
1069
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001070 if (!(config_.use_datagram_transport ||
1071 config_.use_datagram_transport_for_data_channels)) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001072 return nullptr;
1073 }
1074
1075 // Caller (offerer) datagram transport.
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001076 if (offer_datagram_transport_) {
1077 RTC_DCHECK(local);
1078 RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
1079 return std::move(offer_datagram_transport_);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001080 }
1081
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001082 const cricket::TransportDescription* transport_description =
1083 description.GetTransportDescriptionByName(content_info.mid());
1084 RTC_DCHECK(transport_description)
1085 << "Missing transport description for mid=" << content_info.mid();
1086
1087 if (!transport_description->opaque_parameters) {
1088 RTC_LOG(LS_INFO)
1089 << "No opaque transport parameters, not creating datagram transport";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001090 return nullptr;
1091 }
1092
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001093 if (transport_description->opaque_parameters->protocol !=
1094 config_.media_transport_factory->GetTransportName()) {
1095 RTC_LOG(LS_INFO) << "Opaque transport parameters for protocol="
1096 << transport_description->opaque_parameters->protocol
1097 << ", which does not match supported protocol="
1098 << config_.media_transport_factory->GetTransportName();
1099 return nullptr;
1100 }
1101
1102 RTC_DCHECK(!local);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001103 // When bundle is enabled, two JsepTransports are created, and then
1104 // the second transport is destroyed (right away).
1105 // For datagram transport, we don't want to create the second
1106 // datagram transport in the first place.
1107 RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
1108
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001109 MediaTransportSettings settings;
1110 settings.is_caller = local;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001111 settings.remote_transport_parameters =
1112 transport_description->opaque_parameters->parameters;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001113 settings.event_log = config_.event_log;
1114
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001115 auto datagram_transport_result =
1116 config_.media_transport_factory->CreateDatagramTransport(network_thread_,
1117 settings);
1118
1119 // TODO(sukhanov): Proper error handling.
1120 RTC_CHECK(datagram_transport_result.ok());
1121
1122 return datagram_transport_result.MoveValue();
1123}
1124
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001125RTCError JsepTransportController::MaybeCreateJsepTransport(
1126 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001127 const cricket::ContentInfo& content_info,
1128 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001129 RTC_DCHECK(network_thread_->IsCurrent());
1130 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1131 if (transport) {
1132 return RTCError::OK();
1133 }
1134
1135 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001136 content_info.media_description();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001137 if (certificate_ && !content_desc->cryptos().empty()) {
1138 return RTCError(RTCErrorType::INVALID_PARAMETER,
1139 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1140 }
1141
Qingsi Wang25ec8882019-11-15 12:33:05 -08001142 rtc::scoped_refptr<webrtc::IceTransportInterface> ice =
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001143 CreateIceTransport(content_info.name, /*rtcp=*/false);
Qingsi Wang25ec8882019-11-15 12:33:05 -08001144 RTC_DCHECK(ice);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001145
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001146 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1147 MaybeCreateDatagramTransport(content_info, description, local);
1148 if (datagram_transport) {
Qingsi Wang25ec8882019-11-15 12:33:05 -08001149 datagram_transport->Connect(ice->internal());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001150 }
1151
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001152 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Qingsi Wang25ec8882019-11-15 12:33:05 -08001153 CreateDtlsTransport(content_info, ice->internal(), nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001154
1155 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1156 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1157 std::unique_ptr<SrtpTransport> sdes_transport;
1158 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001159 std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001160
Qingsi Wang25ec8882019-11-15 12:33:05 -08001161 rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001162 if (config_.rtcp_mux_policy !=
1163 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1164 content_info.type == cricket::MediaProtocolType::kRtp) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001165 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001166 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
Qingsi Wang25ec8882019-11-15 12:33:05 -08001167 rtcp_dtls_transport =
1168 CreateDtlsTransport(content_info, rtcp_ice->internal(),
1169 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001170 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001171
Bjorn A Mellem703ea952019-08-23 10:31:11 -07001172 // Only create a datagram RTP transport if the datagram transport should be
1173 // used for RTP.
1174 if (datagram_transport && config_.use_datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001175 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1176 // because MediaTransport encrypts. In the future we may want to
1177 // implement our own version of RtpTransport over MediaTransport, because
1178 // it will give us more control over things like:
1179 // - Fusing
1180 // - Rtp header compression
1181 // - Handling Rtcp feedback.
1182 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1183 "transport is used.";
1184 RTC_DCHECK(!rtcp_dtls_transport);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001185 datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
Qingsi Wang25ec8882019-11-15 12:33:05 -08001186 content_info.media_description()->rtp_header_extensions(),
1187 ice->internal(), datagram_transport.get());
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001188 }
1189
1190 if (config_.disable_encryption) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001191 RTC_LOG(LS_INFO)
1192 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001193 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001194 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001195 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001196 sdes_transport = CreateSdesTransport(
1197 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001198 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001199 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001200 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001201 dtls_srtp_transport = CreateDtlsSrtpTransport(
1202 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001203 }
1204
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001205 std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
1206 if (config_.sctp_factory) {
1207 sctp_transport =
1208 config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
1209 }
1210
1211 DataChannelTransportInterface* data_channel_transport = nullptr;
1212 if (config_.use_datagram_transport_for_data_channels) {
1213 data_channel_transport = datagram_transport.get();
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001214 }
1215
Zhi Huang365381f2018-04-13 16:44:34 -07001216 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001217 std::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001218 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1219 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001220 std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
1221 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
Bjorn A Mellem7a9a0922019-11-26 09:19:40 -08001222 std::move(sctp_transport), std::move(datagram_transport),
1223 data_channel_transport);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001224
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001225 jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1226 this, &JsepTransportController::OnRtcpPacketReceived_n);
1227
Zhi Huange818b6e2018-02-22 15:26:27 -08001228 jsep_transport->SignalRtcpMuxActive.connect(
1229 this, &JsepTransportController::UpdateAggregateStates_n);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001230 jsep_transport->SignalDataChannelTransportNegotiated.connect(
1231 this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001232 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001233
Zhi Huangd2248f82018-04-10 14:41:03 -07001234 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1235 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001236 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001237}
1238
1239void JsepTransportController::MaybeDestroyJsepTransport(
1240 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001241 auto jsep_transport = GetJsepTransportByName(mid);
1242 if (!jsep_transport) {
1243 return;
1244 }
1245
1246 // Don't destroy the JsepTransport if there are still media sections referring
1247 // to it.
1248 for (const auto& kv : mid_to_transport_) {
1249 if (kv.second == jsep_transport) {
1250 return;
1251 }
1252 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001253
Zhi Huange830e682018-03-30 10:48:35 -07001254 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001255 UpdateAggregateStates_n();
1256}
1257
1258void JsepTransportController::DestroyAllJsepTransports_n() {
1259 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001260
1261 for (const auto& jsep_transport : jsep_transports_by_name_) {
Bjorn A Mellem7a9a0922019-11-26 09:19:40 -08001262 config_.transport_observer->OnTransportChanged(jsep_transport.first,
1263 nullptr, nullptr, nullptr);
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001264 }
1265
Zhi Huange830e682018-03-30 10:48:35 -07001266 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001267}
1268
1269void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1270 RTC_DCHECK(network_thread_->IsCurrent());
1271
1272 ice_role_ = ice_role;
1273 for (auto& dtls : GetDtlsTransports()) {
1274 dtls->ice_transport()->SetIceRole(ice_role_);
1275 }
1276}
1277
1278cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001279 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001280 const cricket::TransportInfo& transport_info,
1281 SdpType type,
1282 bool local) {
1283 cricket::IceRole ice_role = ice_role_;
1284 auto tdesc = transport_info.description;
1285 if (local) {
1286 // The initial offer side may use ICE Lite, in which case, per RFC5245
1287 // Section 5.1.1, the answer side should take the controlling role if it is
1288 // in the full ICE mode.
1289 //
1290 // When both sides use ICE Lite, the initial offer side must take the
1291 // controlling role, and this is the default logic implemented in
1292 // SetLocalDescription in JsepTransportController.
1293 if (jsep_transport->remote_description() &&
1294 jsep_transport->remote_description()->transport_desc.ice_mode ==
1295 cricket::ICEMODE_LITE &&
1296 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1297 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1298 ice_role = cricket::ICEROLE_CONTROLLING;
1299 }
1300
1301 // Older versions of Chrome expect the ICE role to be re-determined when an
1302 // ICE restart occurs, and also don't perform conflict resolution correctly,
1303 // so for now we can't safely stop doing this, unless the application opts
1304 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1305 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1306 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1307 // enough population.
1308 if (config_.redetermine_role_on_ice_restart &&
1309 jsep_transport->local_description() &&
1310 cricket::IceCredentialsChanged(
1311 jsep_transport->local_description()->transport_desc.ice_ufrag,
1312 jsep_transport->local_description()->transport_desc.ice_pwd,
1313 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1314 // Don't change the ICE role if the remote endpoint is ICE lite; we
1315 // should always be controlling in that case.
1316 (!jsep_transport->remote_description() ||
1317 jsep_transport->remote_description()->transport_desc.ice_mode !=
1318 cricket::ICEMODE_LITE)) {
1319 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1320 : cricket::ICEROLE_CONTROLLED;
1321 }
1322 } else {
1323 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1324 // supports only ice_lite, this local endpoint should take the CONTROLLING
1325 // role.
1326 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1327 // be in a TransportDescription in the first place...
1328 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1329 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1330 ice_role = cricket::ICEROLE_CONTROLLING;
1331 }
1332
1333 // If we use ICE Lite and the remote endpoint uses the full implementation
1334 // of ICE, the local endpoint must take the controlled role, and the other
1335 // side must be the controlling role.
1336 if (jsep_transport->local_description() &&
1337 jsep_transport->local_description()->transport_desc.ice_mode ==
1338 cricket::ICEMODE_LITE &&
1339 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001340 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001341 ice_role = cricket::ICEROLE_CONTROLLED;
1342 }
1343 }
1344
1345 return ice_role;
1346}
1347
1348void JsepTransportController::OnTransportWritableState_n(
1349 rtc::PacketTransportInternal* transport) {
1350 RTC_DCHECK(network_thread_->IsCurrent());
1351 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1352 << " writability changed to " << transport->writable()
1353 << ".";
1354 UpdateAggregateStates_n();
1355}
1356
1357void JsepTransportController::OnTransportReceivingState_n(
1358 rtc::PacketTransportInternal* transport) {
1359 RTC_DCHECK(network_thread_->IsCurrent());
1360 UpdateAggregateStates_n();
1361}
1362
1363void JsepTransportController::OnTransportGatheringState_n(
1364 cricket::IceTransportInternal* transport) {
1365 RTC_DCHECK(network_thread_->IsCurrent());
1366 UpdateAggregateStates_n();
1367}
1368
1369void JsepTransportController::OnTransportCandidateGathered_n(
1370 cricket::IceTransportInternal* transport,
1371 const cricket::Candidate& candidate) {
1372 RTC_DCHECK(network_thread_->IsCurrent());
1373
1374 // We should never signal peer-reflexive candidates.
1375 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1376 RTC_NOTREACHED();
1377 return;
1378 }
Steve Antond25828a2018-08-31 13:06:05 -07001379 std::string transport_name = transport->transport_name();
1380 invoker_.AsyncInvoke<void>(
1381 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1382 SignalIceCandidatesGathered(transport_name, {candidate});
1383 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001384}
1385
Eldar Relloda13ea22019-06-01 12:23:43 +03001386void JsepTransportController::OnTransportCandidateError_n(
1387 cricket::IceTransportInternal* transport,
1388 const cricket::IceCandidateErrorEvent& event) {
1389 RTC_DCHECK(network_thread_->IsCurrent());
1390
1391 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1392 [this, event] { SignalIceCandidateError(event); });
1393}
Zhi Huange818b6e2018-02-22 15:26:27 -08001394void JsepTransportController::OnTransportCandidatesRemoved_n(
1395 cricket::IceTransportInternal* transport,
1396 const cricket::Candidates& candidates) {
1397 invoker_.AsyncInvoke<void>(
1398 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001399 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001400}
Alex Drake00c7ecf2019-08-06 10:54:47 -07001401void JsepTransportController::OnTransportCandidatePairChanged_n(
1402 const cricket::CandidatePairChangeEvent& event) {
1403 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
1404 SignalIceCandidatePairChanged(event);
1405 });
1406}
Zhi Huange818b6e2018-02-22 15:26:27 -08001407
1408void JsepTransportController::OnTransportRoleConflict_n(
1409 cricket::IceTransportInternal* transport) {
1410 RTC_DCHECK(network_thread_->IsCurrent());
1411 // Note: since the role conflict is handled entirely on the network thread,
1412 // we don't need to worry about role conflicts occurring on two ports at
1413 // once. The first one encountered should immediately reverse the role.
1414 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1415 ? cricket::ICEROLE_CONTROLLED
1416 : cricket::ICEROLE_CONTROLLING;
1417 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1418 << (reversed_role == cricket::ICEROLE_CONTROLLING
1419 ? "controlling"
1420 : "controlled")
1421 << " role.";
1422 SetIceRole_n(reversed_role);
1423}
1424
1425void JsepTransportController::OnTransportStateChanged_n(
1426 cricket::IceTransportInternal* transport) {
1427 RTC_DCHECK(network_thread_->IsCurrent());
1428 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1429 << transport->component()
1430 << " state changed. Check if state is complete.";
1431 UpdateAggregateStates_n();
1432}
1433
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001434void JsepTransportController::OnDataChannelTransportNegotiated_n(
1435 cricket::JsepTransport* transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001436 DataChannelTransportInterface* data_channel_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001437 for (auto it : mid_to_transport_) {
1438 if (it.second == transport) {
1439 config_.transport_observer->OnTransportChanged(
1440 it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
Bjorn A Mellem7a9a0922019-11-26 09:19:40 -08001441 data_channel_transport);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001442 }
1443 }
1444}
1445
Zhi Huange818b6e2018-02-22 15:26:27 -08001446void JsepTransportController::UpdateAggregateStates_n() {
1447 RTC_DCHECK(network_thread_->IsCurrent());
1448
1449 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001450 cricket::IceConnectionState new_connection_state =
1451 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001452 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1453 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1454 PeerConnectionInterface::PeerConnectionState new_combined_state =
1455 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001456 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001457 bool any_failed = false;
Alex Loiko9289eda2018-11-23 16:18:59 +00001458 bool all_connected = !dtls_transports.empty();
1459 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001460 bool any_gathering = false;
1461 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001462
1463 std::map<IceTransportState, int> ice_state_counts;
1464 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1465
Zhi Huange818b6e2018-02-22 15:26:27 -08001466 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001467 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1468 cricket::IceTransportState::STATE_FAILED;
1469 all_connected = all_connected && dtls->writable();
1470 all_completed =
1471 all_completed && dtls->writable() &&
1472 dtls->ice_transport()->GetState() ==
1473 cricket::IceTransportState::STATE_COMPLETED &&
1474 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1475 dtls->ice_transport()->gathering_state() ==
1476 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001477 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1478 cricket::kIceGatheringNew;
1479 all_done_gathering =
1480 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1481 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001482
1483 dtls_state_counts[dtls->dtls_state()]++;
1484 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001485 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001486
Alex Loiko9289eda2018-11-23 16:18:59 +00001487 if (any_failed) {
1488 new_connection_state = cricket::kIceConnectionFailed;
1489 } else if (all_completed) {
1490 new_connection_state = cricket::kIceConnectionCompleted;
1491 } else if (all_connected) {
1492 new_connection_state = cricket::kIceConnectionConnected;
1493 }
1494 if (ice_connection_state_ != new_connection_state) {
1495 ice_connection_state_ = new_connection_state;
1496 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1497 [this, new_connection_state] {
1498 SignalIceConnectionState(new_connection_state);
1499 });
1500 }
1501
Jonas Olsson635474e2018-10-18 15:58:17 +02001502 // Compute the current RTCIceConnectionState as described in
1503 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1504 // The PeerConnection is responsible for handling the "closed" state.
1505 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1506 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1507 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1508 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1509 int total_ice_disconnected =
1510 ice_state_counts[IceTransportState::kDisconnected];
1511 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1512 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1513 int total_ice = dtls_transports.size();
1514
1515 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001516 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001517 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001518 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001519 // None of the previous states apply and any RTCIceTransports are in the
1520 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001521 new_ice_connection_state =
1522 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001523 } else if (total_ice_new + total_ice_closed == total_ice) {
1524 // None of the previous states apply and all RTCIceTransports are in the
1525 // "new" or "closed" state, or there are no transports.
1526 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1527 } else if (total_ice_new + total_ice_checking > 0) {
1528 // None of the previous states apply and any RTCIceTransports are in the
1529 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001530 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001531 } else if (total_ice_completed + total_ice_closed == total_ice ||
1532 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001533 // None of the previous states apply and all RTCIceTransports are in the
1534 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001535 //
1536 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1537 // to mimic the behavior of the old ICE connection state, and should be
1538 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001539 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1540 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001541 total_ice) {
1542 // None of the previous states apply and all RTCIceTransports are in the
1543 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001544 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001545 } else {
1546 RTC_NOTREACHED();
1547 }
1548
Alex Loiko9289eda2018-11-23 16:18:59 +00001549 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001550 if (standardized_ice_connection_state_ ==
1551 PeerConnectionInterface::kIceConnectionChecking &&
1552 new_ice_connection_state ==
1553 PeerConnectionInterface::kIceConnectionCompleted) {
1554 // Ensure that we never skip over the "connected" state.
1555 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1556 SignalStandardizedIceConnectionState(
1557 PeerConnectionInterface::kIceConnectionConnected);
1558 });
1559 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001560 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001561 invoker_.AsyncInvoke<void>(
1562 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001563 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001564 });
1565 }
1566
1567 // Compute the current RTCPeerConnectionState as described in
1568 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1569 // The PeerConnection is responsible for handling the "closed" state.
1570 // Note that "connecting" is only a valid state for DTLS transports while
1571 // "checking", "completed" and "disconnected" are only valid for ICE
1572 // transports.
1573 int total_connected = total_ice_connected +
1574 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1575 int total_dtls_connecting =
1576 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1577 int total_failed =
1578 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1579 int total_closed =
1580 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1581 int total_new =
1582 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1583 int total_transports = total_ice * 2;
1584
1585 if (total_failed > 0) {
1586 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1587 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001588 } else if (total_ice_disconnected > 0) {
1589 // None of the previous states apply and any RTCIceTransports or
1590 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001591 new_combined_state =
1592 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001593 } else if (total_new + total_closed == total_transports) {
1594 // None of the previous states apply and all RTCIceTransports and
1595 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1596 // transports.
1597 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1598 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1599 // None of the previous states apply and all RTCIceTransports or
1600 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001601 new_combined_state =
1602 PeerConnectionInterface::PeerConnectionState::kConnecting;
1603 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001604 total_transports) {
1605 // None of the previous states apply and all RTCIceTransports and
1606 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001607 new_combined_state =
1608 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001609 } else {
1610 RTC_NOTREACHED();
1611 }
1612
1613 if (combined_connection_state_ != new_combined_state) {
1614 combined_connection_state_ = new_combined_state;
1615 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1616 [this, new_combined_state] {
1617 SignalConnectionState(new_combined_state);
1618 });
1619 }
1620
Zhi Huange818b6e2018-02-22 15:26:27 -08001621 if (all_done_gathering) {
1622 new_gathering_state = cricket::kIceGatheringComplete;
1623 } else if (any_gathering) {
1624 new_gathering_state = cricket::kIceGatheringGathering;
1625 }
1626 if (ice_gathering_state_ != new_gathering_state) {
1627 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001628 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1629 [this, new_gathering_state] {
1630 SignalIceGatheringState(new_gathering_state);
1631 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001632 }
1633}
1634
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001635void JsepTransportController::OnRtcpPacketReceived_n(
1636 rtc::CopyOnWriteBuffer* packet,
1637 int64_t packet_time_us) {
1638 RTC_DCHECK(config_.rtcp_handler);
1639 config_.rtcp_handler(*packet, packet_time_us);
1640}
1641
Zhi Huange818b6e2018-02-22 15:26:27 -08001642void JsepTransportController::OnDtlsHandshakeError(
1643 rtc::SSLHandshakeError error) {
1644 SignalDtlsHandshakeError(error);
1645}
1646
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001647absl::optional<cricket::OpaqueTransportParameters>
1648JsepTransportController::GetTransportParameters(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001649 if (!(config_.use_datagram_transport ||
1650 config_.use_datagram_transport_for_data_channels)) {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001651 return absl::nullopt;
1652 }
1653
1654 cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
1655 if (transport) {
1656 absl::optional<cricket::OpaqueTransportParameters> params =
1657 transport->GetTransportParameters();
1658 if (params) {
1659 params->protocol = config_.media_transport_factory->GetTransportName();
1660 }
1661 return params;
1662 }
1663
1664 RTC_DCHECK(!local_desc_ && !remote_desc_)
1665 << "JsepTransport should exist for every mid once any description is set";
1666
Bjorn A Mellem7da4e562019-09-26 11:02:11 -07001667 if (config_.use_datagram_transport_for_data_channels_receive_only) {
1668 return absl::nullopt;
1669 }
1670
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001671 // Need to generate a transport for the offer.
1672 if (!offer_datagram_transport_) {
1673 webrtc::MediaTransportSettings settings;
1674 settings.is_caller = true;
1675 settings.pre_shared_key = rtc::CreateRandomString(32);
1676 settings.event_log = config_.event_log;
1677 auto datagram_transport_or_error =
1678 config_.media_transport_factory->CreateDatagramTransport(
1679 network_thread_, settings);
1680
1681 if (datagram_transport_or_error.ok()) {
1682 offer_datagram_transport_ =
1683 std::move(datagram_transport_or_error.value());
1684 } else {
1685 RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
1686 << datagram_transport_or_error.error().message();
1687 }
1688 }
1689
1690 // We have prepared a transport for the offer, and can now use its parameters.
1691 cricket::OpaqueTransportParameters params;
1692 params.parameters = offer_datagram_transport_->GetTransportParameters();
1693 params.protocol = config_.media_transport_factory->GetTransportName();
1694 return params;
1695}
1696
Zhi Huange818b6e2018-02-22 15:26:27 -08001697} // namespace webrtc