blob: 4f7000964f56065a5b6a6b19f8eb54749bc51bae [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"
Niels Möller65f17ca2019-09-12 13:59:36 +020017#include "api/transport/datagram_transport_interface.h"
18#include "api/transport/media/media_transport_interface.h"
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -080019#include "p2p/base/ice_transport_internal.h"
20#include "p2p/base/no_op_dtls_transport.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);
92}
Zhi Huange818b6e2018-02-22 15:26:27 -080093
94JsepTransportController::~JsepTransportController() {
95 // Channel destructors may try to send packets, so this needs to happen on
96 // the network thread.
97 network_thread_->Invoke<void>(
98 RTC_FROM_HERE,
99 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
100}
101
102RTCError JsepTransportController::SetLocalDescription(
103 SdpType type,
104 const cricket::SessionDescription* description) {
105 if (!network_thread_->IsCurrent()) {
106 return network_thread_->Invoke<RTCError>(
107 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
108 }
109
110 if (!initial_offerer_.has_value()) {
111 initial_offerer_.emplace(type == SdpType::kOffer);
112 if (*initial_offerer_) {
113 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
114 } else {
115 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
116 }
117 }
118 return ApplyDescription_n(/*local=*/true, type, description);
119}
120
121RTCError JsepTransportController::SetRemoteDescription(
122 SdpType type,
123 const cricket::SessionDescription* description) {
124 if (!network_thread_->IsCurrent()) {
125 return network_thread_->Invoke<RTCError>(
126 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
127 }
128
129 return ApplyDescription_n(/*local=*/false, type, description);
130}
131
132RtpTransportInternal* JsepTransportController::GetRtpTransport(
133 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700134 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800135 if (!jsep_transport) {
136 return nullptr;
137 }
138 return jsep_transport->rtp_transport();
139}
140
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700141MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700142 const std::string& mid) const {
143 auto jsep_transport = GetJsepTransportForMid(mid);
144 if (!jsep_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700145 return MediaTransportConfig();
146 }
147
148 MediaTransportInterface* media_transport = nullptr;
149 if (config_.use_media_transport_for_media) {
150 media_transport = jsep_transport->media_transport();
151 }
152
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700153 DatagramTransportInterface* datagram_transport = nullptr;
154 if (config_.use_datagram_transport) {
155 datagram_transport = jsep_transport->datagram_transport();
156 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700157
158 // Media transport and datagram transports can not be used together.
159 RTC_DCHECK(!media_transport || !datagram_transport);
160
161 if (media_transport) {
162 return MediaTransportConfig(media_transport);
163 } else if (datagram_transport) {
164 return MediaTransportConfig(
165 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
166 } else {
167 return MediaTransportConfig();
168 }
169}
170
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700171DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700172 const std::string& mid) const {
173 auto jsep_transport = GetJsepTransportForMid(mid);
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700174 if (!jsep_transport) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700175 return nullptr;
176 }
Qingsi Wang437077d2019-09-10 17:52:26 +0000177
178 if (config_.use_media_transport_for_data_channels) {
179 return jsep_transport->media_transport();
180 } else if (config_.use_datagram_transport_for_data_channels) {
181 return jsep_transport->datagram_transport();
182 }
183 // Not configured to use a data channel transport.
184 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -0700185}
186
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800187MediaTransportState JsepTransportController::GetMediaTransportState(
188 const std::string& mid) const {
189 auto jsep_transport = GetJsepTransportForMid(mid);
190 if (!jsep_transport) {
191 return MediaTransportState::kPending;
192 }
193 return jsep_transport->media_transport_state();
194}
195
Zhi Huange818b6e2018-02-22 15:26:27 -0800196cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100197 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700198 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800199 if (!jsep_transport) {
200 return nullptr;
201 }
202 return jsep_transport->rtp_dtls_transport();
203}
204
Harald Alvestrandad88c882018-11-28 16:47:46 +0100205const cricket::DtlsTransportInternal*
206JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700207 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800208 if (!jsep_transport) {
209 return nullptr;
210 }
211 return jsep_transport->rtcp_dtls_transport();
212}
213
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100214rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100215JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
216 auto jsep_transport = GetJsepTransportForMid(mid);
217 if (!jsep_transport) {
218 return nullptr;
219 }
220 return jsep_transport->RtpDtlsTransport();
221}
222
Zhi Huange818b6e2018-02-22 15:26:27 -0800223void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
224 if (!network_thread_->IsCurrent()) {
225 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
226 return;
227 }
228
229 ice_config_ = config;
230 for (auto& dtls : GetDtlsTransports()) {
231 dtls->ice_transport()->SetIceConfig(ice_config_);
232 }
233}
234
235void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700236 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800237 kv.second->SetNeedsIceRestartFlag();
238 }
239}
240
241bool JsepTransportController::NeedsIceRestart(
242 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700243 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700244 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800245 if (!transport) {
246 return false;
247 }
248 return transport->needs_ice_restart();
249}
250
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200251absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700252 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800253 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200254 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700255 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800256 }
257
Zhi Huang365381f2018-04-13 16:44:34 -0700258 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800259 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200260 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800261 }
262 return t->GetDtlsRole();
263}
264
265bool JsepTransportController::SetLocalCertificate(
266 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
267 if (!network_thread_->IsCurrent()) {
268 return network_thread_->Invoke<bool>(
269 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
270 }
271
272 // Can't change a certificate, or set a null certificate.
273 if (certificate_ || !certificate) {
274 return false;
275 }
276 certificate_ = certificate;
277
278 // Set certificate for JsepTransport, which verifies it matches the
279 // fingerprint in SDP, and DTLS transport.
280 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700281 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800282 kv.second->SetLocalCertificate(certificate_);
283 }
284 for (auto& dtls : GetDtlsTransports()) {
285 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
286 RTC_DCHECK(set_cert_success);
287 }
288 return true;
289}
290
291rtc::scoped_refptr<rtc::RTCCertificate>
292JsepTransportController::GetLocalCertificate(
293 const std::string& transport_name) const {
294 if (!network_thread_->IsCurrent()) {
295 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
296 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
297 }
298
Zhi Huang365381f2018-04-13 16:44:34 -0700299 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800300 if (!t) {
301 return nullptr;
302 }
303 return t->GetLocalCertificate();
304}
305
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800306std::unique_ptr<rtc::SSLCertChain>
307JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800308 const std::string& transport_name) const {
309 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800310 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
311 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800312 }
313
Zhi Huange830e682018-03-30 10:48:35 -0700314 // Get the certificate from the RTP transport's DTLS handshake. Should be
315 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800316 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700317 auto jsep_transport = GetJsepTransportByName(transport_name);
318 if (!jsep_transport) {
319 return nullptr;
320 }
321 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800322 if (!dtls) {
323 return nullptr;
324 }
325
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800326 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800327}
328
329void JsepTransportController::MaybeStartGathering() {
330 if (!network_thread_->IsCurrent()) {
331 network_thread_->Invoke<void>(RTC_FROM_HERE,
332 [&] { MaybeStartGathering(); });
333 return;
334 }
335
336 for (auto& dtls : GetDtlsTransports()) {
337 dtls->ice_transport()->MaybeStartGathering();
338 }
339}
340
341RTCError JsepTransportController::AddRemoteCandidates(
342 const std::string& transport_name,
343 const cricket::Candidates& candidates) {
344 if (!network_thread_->IsCurrent()) {
345 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
346 return AddRemoteCandidates(transport_name, candidates);
347 });
348 }
349
350 // Verify each candidate before passing down to the transport layer.
351 RTCError error = VerifyCandidates(candidates);
352 if (!error.ok()) {
353 return error;
354 }
Zhi Huange830e682018-03-30 10:48:35 -0700355 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800356 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700357 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
358 "doesn't exist. Ignore it.";
359 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800360 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800361 return jsep_transport->AddRemoteCandidates(candidates);
362}
363
364RTCError JsepTransportController::RemoveRemoteCandidates(
365 const cricket::Candidates& candidates) {
366 if (!network_thread_->IsCurrent()) {
367 return network_thread_->Invoke<RTCError>(
368 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
369 }
370
371 // Verify each candidate before passing down to the transport layer.
372 RTCError error = VerifyCandidates(candidates);
373 if (!error.ok()) {
374 return error;
375 }
376
377 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
378 for (const cricket::Candidate& cand : candidates) {
379 if (!cand.transport_name().empty()) {
380 candidates_by_transport_name[cand.transport_name()].push_back(cand);
381 } else {
382 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
383 "transport name set: "
Qingsi Wang20232a92019-09-06 12:51:17 -0700384 << cand.ToSensitiveString();
Zhi Huange818b6e2018-02-22 15:26:27 -0800385 }
386 }
387
388 for (const auto& kv : candidates_by_transport_name) {
389 const std::string& transport_name = kv.first;
390 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700391 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700392 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800393 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700394 RTC_LOG(LS_WARNING)
395 << "Not removing candidate because the JsepTransport doesn't exist.";
396 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800397 }
398 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100399 cricket::DtlsTransportInternal* dtls =
400 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
401 ? jsep_transport->rtp_dtls_transport()
402 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800403 if (dtls) {
404 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
405 }
406 }
407 }
408 return RTCError::OK();
409}
410
411bool JsepTransportController::GetStats(const std::string& transport_name,
412 cricket::TransportStats* stats) {
413 if (!network_thread_->IsCurrent()) {
414 return network_thread_->Invoke<bool>(
415 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
416 }
417
Zhi Huang365381f2018-04-13 16:44:34 -0700418 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800419 if (!transport) {
420 return false;
421 }
422 return transport->GetStats(stats);
423}
424
Zhi Huangb57e1692018-06-12 11:41:11 -0700425void JsepTransportController::SetActiveResetSrtpParams(
426 bool active_reset_srtp_params) {
427 if (!network_thread_->IsCurrent()) {
428 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
429 SetActiveResetSrtpParams(active_reset_srtp_params);
430 });
431 return;
432 }
433
434 RTC_LOG(INFO)
435 << "Updating the active_reset_srtp_params for JsepTransportController: "
436 << active_reset_srtp_params;
437 config_.active_reset_srtp_params = active_reset_srtp_params;
438 for (auto& kv : jsep_transports_by_name_) {
439 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
440 }
441}
442
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800443void JsepTransportController::SetMediaTransportSettings(
444 bool use_media_transport_for_media,
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700445 bool use_media_transport_for_data_channels,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700446 bool use_datagram_transport,
447 bool use_datagram_transport_for_data_channels) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800448 RTC_DCHECK(use_media_transport_for_media ==
449 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700450 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800451 << "You can only change media transport configuration before creating "
452 "the first transport.";
453
454 RTC_DCHECK(use_media_transport_for_data_channels ==
455 config_.use_media_transport_for_data_channels ||
456 jsep_transports_by_name_.empty())
457 << "You can only change media transport configuration before creating "
458 "the first transport.";
459
460 config_.use_media_transport_for_media = use_media_transport_for_media;
461 config_.use_media_transport_for_data_channels =
462 use_media_transport_for_data_channels;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700463 config_.use_datagram_transport = use_datagram_transport;
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700464 config_.use_datagram_transport_for_data_channels =
465 use_datagram_transport_for_data_channels;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700466}
467
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800468std::unique_ptr<cricket::IceTransportInternal>
469JsepTransportController::CreateIceTransport(const std::string transport_name,
470 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800471 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
472 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
473
Zhi Huange818b6e2018-02-22 15:26:27 -0800474 if (config_.external_transport_factory) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800475 return config_.external_transport_factory->CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -0800476 transport_name, component);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800477 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200478 return std::make_unique<cricket::P2PTransportChannel>(
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800479 transport_name, component, port_allocator_, async_resolver_factory_,
480 config_.event_log);
481 }
482}
483
484std::unique_ptr<cricket::DtlsTransportInternal>
485JsepTransportController::CreateDtlsTransport(
Anton Sukhanovac6c0962019-07-10 15:44:56 -0700486 const cricket::ContentInfo& content_info,
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700487 cricket::IceTransportInternal* ice,
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700488 DatagramTransportInterface* datagram_transport) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800489 RTC_DCHECK(network_thread_->IsCurrent());
490
491 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700492
493 if (datagram_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700494 RTC_DCHECK(config_.use_datagram_transport ||
495 config_.use_datagram_transport_for_data_channels);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700496 } else if (config_.media_transport_factory &&
497 config_.use_media_transport_for_media &&
498 config_.use_media_transport_for_data_channels) {
499 // If media transport is used for both media and data channels,
500 // then we don't need to create DTLS.
501 // Otherwise, DTLS is still created.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200502 dtls = std::make_unique<cricket::NoOpDtlsTransport>(ice,
503 config_.crypto_options);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800504 } else if (config_.external_transport_factory) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800505 dtls = config_.external_transport_factory->CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700506 ice, config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800507 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200508 dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
509 config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800510 }
511
512 RTC_DCHECK(dtls);
513 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800514 dtls->ice_transport()->SetIceRole(ice_role_);
515 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
516 dtls->ice_transport()->SetIceConfig(ice_config_);
517 if (certificate_) {
518 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
519 RTC_DCHECK(set_cert_success);
520 }
521
522 // Connect to signals offered by the DTLS and ICE transport.
523 dtls->SignalWritableState.connect(
524 this, &JsepTransportController::OnTransportWritableState_n);
525 dtls->SignalReceivingState.connect(
526 this, &JsepTransportController::OnTransportReceivingState_n);
527 dtls->SignalDtlsHandshakeError.connect(
528 this, &JsepTransportController::OnDtlsHandshakeError);
529 dtls->ice_transport()->SignalGatheringState.connect(
530 this, &JsepTransportController::OnTransportGatheringState_n);
531 dtls->ice_transport()->SignalCandidateGathered.connect(
532 this, &JsepTransportController::OnTransportCandidateGathered_n);
Eldar Relloda13ea22019-06-01 12:23:43 +0300533 dtls->ice_transport()->SignalCandidateError.connect(
534 this, &JsepTransportController::OnTransportCandidateError_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800535 dtls->ice_transport()->SignalCandidatesRemoved.connect(
536 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
537 dtls->ice_transport()->SignalRoleConflict.connect(
538 this, &JsepTransportController::OnTransportRoleConflict_n);
539 dtls->ice_transport()->SignalStateChanged.connect(
540 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100541 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
542 this, &JsepTransportController::OnTransportStateChanged_n);
Alex Drake00c7ecf2019-08-06 10:54:47 -0700543 dtls->ice_transport()->SignalCandidatePairChanged.connect(
544 this, &JsepTransportController::OnTransportCandidatePairChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800545 return dtls;
546}
547
548std::unique_ptr<webrtc::RtpTransport>
549JsepTransportController::CreateUnencryptedRtpTransport(
550 const std::string& transport_name,
551 rtc::PacketTransportInternal* rtp_packet_transport,
552 rtc::PacketTransportInternal* rtcp_packet_transport) {
553 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700554 auto unencrypted_rtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200555 std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700556 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
557 if (rtcp_packet_transport) {
558 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
559 }
560 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800561}
562
563std::unique_ptr<webrtc::SrtpTransport>
564JsepTransportController::CreateSdesTransport(
565 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700566 cricket::DtlsTransportInternal* rtp_dtls_transport,
567 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800568 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800569 auto srtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200570 std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700571 RTC_DCHECK(rtp_dtls_transport);
572 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
573 if (rtcp_dtls_transport) {
574 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800575 }
576 if (config_.enable_external_auth) {
577 srtp_transport->EnableExternalAuth();
578 }
579 return srtp_transport;
580}
581
582std::unique_ptr<webrtc::DtlsSrtpTransport>
583JsepTransportController::CreateDtlsSrtpTransport(
584 const std::string& transport_name,
585 cricket::DtlsTransportInternal* rtp_dtls_transport,
586 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
587 RTC_DCHECK(network_thread_->IsCurrent());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200588 auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700589 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700590 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700591 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700592 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000593
Zhi Huange818b6e2018-02-22 15:26:27 -0800594 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
595 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700596 dtls_srtp_transport->SetActiveResetSrtpParams(
597 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200598 dtls_srtp_transport->SignalDtlsStateChange.connect(
599 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800600 return dtls_srtp_transport;
601}
602
603std::vector<cricket::DtlsTransportInternal*>
604JsepTransportController::GetDtlsTransports() {
605 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700606 for (auto it = jsep_transports_by_name_.begin();
607 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800608 auto jsep_transport = it->second.get();
609 RTC_DCHECK(jsep_transport);
610 if (jsep_transport->rtp_dtls_transport()) {
611 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
612 }
613
614 if (jsep_transport->rtcp_dtls_transport()) {
615 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
616 }
617 }
618 return dtls_transports;
619}
620
Zhi Huange818b6e2018-02-22 15:26:27 -0800621RTCError JsepTransportController::ApplyDescription_n(
622 bool local,
623 SdpType type,
624 const cricket::SessionDescription* description) {
625 RTC_DCHECK(network_thread_->IsCurrent());
626 RTC_DCHECK(description);
627
628 if (local) {
629 local_desc_ = description;
630 } else {
631 remote_desc_ = description;
632 }
633
Zhi Huange830e682018-03-30 10:48:35 -0700634 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700635 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700636 if (!error.ok()) {
637 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800638 }
639
640 std::vector<int> merged_encrypted_extension_ids;
641 if (bundle_group_) {
642 merged_encrypted_extension_ids =
643 MergeEncryptedHeaderExtensionIdsForBundle(description);
644 }
645
646 for (const cricket::ContentInfo& content_info : description->contents()) {
647 // Don't create transports for rejected m-lines and bundled m-lines."
648 if (content_info.rejected ||
649 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
650 continue;
651 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800652 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700653 if (!error.ok()) {
654 return error;
655 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800656 }
657
658 RTC_DCHECK(description->contents().size() ==
659 description->transport_infos().size());
660 for (size_t i = 0; i < description->contents().size(); ++i) {
661 const cricket::ContentInfo& content_info = description->contents()[i];
662 const cricket::TransportInfo& transport_info =
663 description->transport_infos()[i];
664 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700665 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800666 continue;
667 }
668
669 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700670 if (!HandleBundledContent(content_info)) {
671 return RTCError(RTCErrorType::INVALID_PARAMETER,
672 "Failed to process the bundled m= section.");
673 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800674 continue;
675 }
676
Zhi Huange830e682018-03-30 10:48:35 -0700677 error = ValidateContent(content_info);
678 if (!error.ok()) {
679 return error;
680 }
681
Zhi Huange818b6e2018-02-22 15:26:27 -0800682 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700683 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800684 extension_ids = merged_encrypted_extension_ids;
685 } else {
686 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
687 }
688
Zhi Huange830e682018-03-30 10:48:35 -0700689 int rtp_abs_sendtime_extn_id =
690 GetRtpAbsSendTimeHeaderExtensionId(content_info);
691
Zhi Huang365381f2018-04-13 16:44:34 -0700692 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700693 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800694 RTC_DCHECK(transport);
695
696 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
697
Zhi Huange818b6e2018-02-22 15:26:27 -0800698 cricket::JsepTransportDescription jsep_description =
699 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700700 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800701 if (local) {
702 error =
703 transport->SetLocalJsepTransportDescription(jsep_description, type);
704 } else {
705 error =
706 transport->SetRemoteJsepTransportDescription(jsep_description, type);
707 }
708
709 if (!error.ok()) {
710 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
711 "Failed to apply the description for " +
712 content_info.name + ": " + error.message());
713 }
714 }
715 return RTCError::OK();
716}
717
Zhi Huangd2248f82018-04-10 14:41:03 -0700718RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
719 bool local,
720 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700721 const cricket::SessionDescription* description) {
722 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700723 const cricket::ContentGroup* new_bundle_group =
724 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
725
726 // The BUNDLE group containing a MID that no m= section has is invalid.
727 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100728 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700729 if (!description->GetContentByName(content_name)) {
730 return RTCError(RTCErrorType::INVALID_PARAMETER,
731 "The BUNDLE group contains MID:" + content_name +
732 " matching no m= section.");
733 }
734 }
735 }
736
737 if (type == SdpType::kAnswer) {
738 const cricket::ContentGroup* offered_bundle_group =
739 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
740 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
741
742 if (new_bundle_group) {
743 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100744 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700745 if (!offered_bundle_group ||
746 !offered_bundle_group->HasContentName(content_name)) {
747 return RTCError(RTCErrorType::INVALID_PARAMETER,
748 "The BUNDLE group in answer contains a MID that was "
749 "not in the offered group.");
750 }
751 }
752 }
753
754 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100755 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700756 // An answer that removes m= sections from pre-negotiated BUNDLE group
757 // without rejecting it, is invalid.
758 if (!new_bundle_group ||
759 !new_bundle_group->HasContentName(content_name)) {
760 auto* content_info = description->GetContentByName(content_name);
761 if (!content_info || !content_info->rejected) {
762 return RTCError(RTCErrorType::INVALID_PARAMETER,
763 "Answer cannot remove m= section " + content_name +
764 " from already-established BUNDLE group.");
765 }
766 }
767 }
768 }
769 }
770
771 if (config_.bundle_policy ==
772 PeerConnectionInterface::kBundlePolicyMaxBundle &&
773 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
774 return RTCError(RTCErrorType::INVALID_PARAMETER,
775 "max-bundle is used but no bundle group found.");
776 }
777
778 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700779 bundle_group_ = *new_bundle_group;
780 }
Zhi Huange830e682018-03-30 10:48:35 -0700781
782 if (!bundled_mid()) {
783 return RTCError::OK();
784 }
785
786 auto bundled_content = description->GetContentByName(*bundled_mid());
787 if (!bundled_content) {
788 return RTCError(
789 RTCErrorType::INVALID_PARAMETER,
790 "An m= section associated with the BUNDLE-tag doesn't exist.");
791 }
792
793 // If the |bundled_content| is rejected, other contents in the bundle group
794 // should be rejected.
795 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100796 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700797 auto other_content = description->GetContentByName(content_name);
798 if (!other_content->rejected) {
799 return RTCError(
800 RTCErrorType::INVALID_PARAMETER,
801 "The m= section:" + content_name + " should be rejected.");
802 }
803 }
804 }
805
806 return RTCError::OK();
807}
808
809RTCError JsepTransportController::ValidateContent(
810 const cricket::ContentInfo& content_info) {
811 if (config_.rtcp_mux_policy ==
812 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
813 content_info.type == cricket::MediaProtocolType::kRtp &&
814 !content_info.media_description()->rtcp_mux()) {
815 return RTCError(RTCErrorType::INVALID_PARAMETER,
816 "The m= section:" + content_info.name +
817 " is invalid. RTCP-MUX is not "
818 "enabled when it is required.");
819 }
820 return RTCError::OK();
821}
822
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700823void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700824 const cricket::ContentInfo& content_info,
825 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800826 // If the content is rejected, let the
827 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700828 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700829 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700830 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100831 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700832 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700833 }
834 bundle_group_.reset();
835 } else if (IsBundled(content_info.name)) {
836 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800837 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700838 // Reset the bundle group if nothing left.
839 if (!bundle_group_->FirstContentName()) {
840 bundle_group_.reset();
841 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800842 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700843 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800844}
845
Zhi Huang365381f2018-04-13 16:44:34 -0700846bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800847 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700848 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
849 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800850 // If the content is bundled, let the
851 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700852 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700853 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800854 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
855 // because it means that we first create media transport and start
856 // connecting it, and then we destroy it. We will need to address it before
857 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700858 MaybeDestroyJsepTransport(content_info.name);
859 return true;
860 }
861 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800862}
863
Zhi Huang365381f2018-04-13 16:44:34 -0700864bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700865 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700866 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700867 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700868 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700869 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700870 }
871
872 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700873 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100874 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
Qingsi Wang437077d2019-09-10 17:52:26 +0000875 jsep_transport->media_transport(), jsep_transport->datagram_transport(),
876 NegotiationState::kInitial);
Zhi Huangd2248f82018-04-10 14:41:03 -0700877}
878
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700879void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700880 bool ret = config_.transport_observer->OnTransportChanged(
Qingsi Wang437077d2019-09-10 17:52:26 +0000881 mid, nullptr, nullptr, nullptr, nullptr, NegotiationState::kFinal);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700882 // Calling OnTransportChanged with nullptr should always succeed, since it is
883 // only expected to fail when adding media to a transport (not removing).
884 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700885 mid_to_transport_.erase(mid);
886}
887
Zhi Huange818b6e2018-02-22 15:26:27 -0800888cricket::JsepTransportDescription
889JsepTransportController::CreateJsepTransportDescription(
Harald Alvestrand1716d392019-06-03 20:35:45 +0200890 const cricket::ContentInfo& content_info,
891 const cricket::TransportInfo& transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700892 const std::vector<int>& encrypted_extension_ids,
893 int rtp_abs_sendtime_extn_id) {
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,
Zhi Huange830e682018-03-30 10:48:35 -0700903 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800904}
905
906bool JsepTransportController::ShouldUpdateBundleGroup(
907 SdpType type,
908 const cricket::SessionDescription* description) {
909 if (config_.bundle_policy ==
910 PeerConnectionInterface::kBundlePolicyMaxBundle) {
911 return true;
912 }
913
914 if (type != SdpType::kAnswer) {
915 return false;
916 }
917
918 RTC_DCHECK(local_desc_ && remote_desc_);
919 const cricket::ContentGroup* local_bundle =
920 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
921 const cricket::ContentGroup* remote_bundle =
922 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
923 return local_bundle && remote_bundle;
924}
925
926std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
927 const cricket::ContentInfo& content_info) {
928 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200929 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800930
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700931 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800932 return std::vector<int>();
933 }
934
935 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100936 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800937 if (!extension.encrypt) {
938 continue;
939 }
Steve Anton64b626b2019-01-28 17:25:26 -0800940 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800941 encrypted_header_extension_ids.push_back(extension.id);
942 }
943 }
944 return encrypted_header_extension_ids;
945}
946
947std::vector<int>
948JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
949 const cricket::SessionDescription* description) {
950 RTC_DCHECK(description);
951 RTC_DCHECK(bundle_group_);
952
953 std::vector<int> merged_ids;
954 // Union the encrypted header IDs in the group when bundle is enabled.
955 for (const cricket::ContentInfo& content_info : description->contents()) {
956 if (bundle_group_->HasContentName(content_info.name)) {
957 std::vector<int> extension_ids =
958 GetEncryptedHeaderExtensionIds(content_info);
959 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -0800960 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800961 merged_ids.push_back(id);
962 }
963 }
964 }
965 }
966 return merged_ids;
967}
968
Zhi Huange830e682018-03-30 10:48:35 -0700969int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800970 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700971 if (!config_.enable_external_auth) {
972 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800973 }
974
975 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200976 content_info.media_description();
Zhi Huange830e682018-03-30 10:48:35 -0700977
978 const webrtc::RtpExtension* send_time_extension =
979 webrtc::RtpExtension::FindHeaderExtensionByUri(
980 content_desc->rtp_header_extensions(),
981 webrtc::RtpExtension::kAbsSendTimeUri);
982 return send_time_extension ? send_time_extension->id : -1;
983}
984
Zhi Huang365381f2018-04-13 16:44:34 -0700985const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700986 const std::string& mid) const {
Zhi Huangd2248f82018-04-10 14:41:03 -0700987 auto it = mid_to_transport_.find(mid);
988 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700989}
990
Zhi Huang365381f2018-04-13 16:44:34 -0700991cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700992 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700993 auto it = mid_to_transport_.find(mid);
994 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -0700995}
996
Zhi Huang365381f2018-04-13 16:44:34 -0700997const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -0700998 const std::string& transport_name) const {
999 auto it = jsep_transports_by_name_.find(transport_name);
1000 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1001}
1002
Zhi Huang365381f2018-04-13 16:44:34 -07001003cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001004 const std::string& transport_name) {
1005 auto it = jsep_transports_by_name_.find(transport_name);
1006 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1007}
1008
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001009std::unique_ptr<webrtc::MediaTransportInterface>
1010JsepTransportController::MaybeCreateMediaTransport(
1011 const cricket::ContentInfo& content_info,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001012 const cricket::SessionDescription& description,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001013 bool local) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001014 if (config_.media_transport_factory == nullptr) {
1015 return nullptr;
1016 }
1017
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001018 if (!config_.use_media_transport_for_media &&
1019 !config_.use_media_transport_for_data_channels) {
1020 return nullptr;
1021 }
1022
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001023 // Caller (offerer) media transport.
1024 if (local) {
1025 if (offer_media_transport_) {
1026 RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
1027 return std::move(offer_media_transport_);
1028 } else {
1029 RTC_LOG(LS_INFO)
1030 << "Not returning media transport. Either SDES wasn't enabled, or "
1031 "media transport didn't return an offer earlier.";
1032 // Offer wasn't generated. Either because media transport didn't want it,
1033 // or because SDES wasn't enabled.
1034 return nullptr;
1035 }
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001036 }
1037
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001038 // Remote offer. If no x-mt lines, do not create media transport.
1039 if (description.MediaTransportSettings().empty()) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001040 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -07001041 }
1042
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001043 // When bundle is enabled, two JsepTransports are created, and then
1044 // the second transport is destroyed (right away).
1045 // For media transport, we don't want to create the second
1046 // media transport in the first place.
1047 RTC_LOG(LS_INFO) << "Returning new, client media transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001048
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001049 RTC_DCHECK(!local)
1050 << "If media transport is used, you must call "
1051 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1052 "also "
1053 "must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
1054 "transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001055 MediaTransportSettings settings;
1056 settings.is_caller = local;
Piotr (Peter) Slatala01fe3092019-02-15 12:05:50 -08001057 if (config_.use_media_transport_for_media) {
1058 settings.event_log = config_.event_log;
1059 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001060
1061 // Assume there is only one media transport (or if more, use the first one).
1062 if (!local && !description.MediaTransportSettings().empty() &&
1063 config_.media_transport_factory->GetTransportName() ==
1064 description.MediaTransportSettings()[0].transport_name) {
1065 settings.remote_transport_parameters =
1066 description.MediaTransportSettings()[0].transport_setting;
1067 }
1068
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001069 auto media_transport_result =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001070 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1071 settings);
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001072
1073 // TODO(sukhanov): Proper error handling.
1074 RTC_CHECK(media_transport_result.ok());
1075
1076 return media_transport_result.MoveValue();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001077}
1078
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001079// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
1080// transports setup.
1081std::unique_ptr<webrtc::DatagramTransportInterface>
1082JsepTransportController::MaybeCreateDatagramTransport(
1083 const cricket::ContentInfo& content_info,
1084 const cricket::SessionDescription& description,
1085 bool local) {
1086 if (config_.media_transport_factory == nullptr) {
1087 return nullptr;
1088 }
1089
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001090 if (!(config_.use_datagram_transport ||
1091 config_.use_datagram_transport_for_data_channels)) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001092 return nullptr;
1093 }
1094
1095 // Caller (offerer) datagram transport.
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001096 if (offer_datagram_transport_) {
1097 RTC_DCHECK(local);
1098 RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
1099 return std::move(offer_datagram_transport_);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001100 }
1101
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001102 const cricket::TransportDescription* transport_description =
1103 description.GetTransportDescriptionByName(content_info.mid());
1104 RTC_DCHECK(transport_description)
1105 << "Missing transport description for mid=" << content_info.mid();
1106
1107 if (!transport_description->opaque_parameters) {
1108 RTC_LOG(LS_INFO)
1109 << "No opaque transport parameters, not creating datagram transport";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001110 return nullptr;
1111 }
1112
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001113 if (transport_description->opaque_parameters->protocol !=
1114 config_.media_transport_factory->GetTransportName()) {
1115 RTC_LOG(LS_INFO) << "Opaque transport parameters for protocol="
1116 << transport_description->opaque_parameters->protocol
1117 << ", which does not match supported protocol="
1118 << config_.media_transport_factory->GetTransportName();
1119 return nullptr;
1120 }
1121
1122 RTC_DCHECK(!local);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001123 // When bundle is enabled, two JsepTransports are created, and then
1124 // the second transport is destroyed (right away).
1125 // For datagram transport, we don't want to create the second
1126 // datagram transport in the first place.
1127 RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
1128
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001129 MediaTransportSettings settings;
1130 settings.is_caller = local;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001131 settings.remote_transport_parameters =
1132 transport_description->opaque_parameters->parameters;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001133 settings.event_log = config_.event_log;
1134
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001135 auto datagram_transport_result =
1136 config_.media_transport_factory->CreateDatagramTransport(network_thread_,
1137 settings);
1138
1139 // TODO(sukhanov): Proper error handling.
1140 RTC_CHECK(datagram_transport_result.ok());
1141
1142 return datagram_transport_result.MoveValue();
1143}
1144
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001145RTCError JsepTransportController::MaybeCreateJsepTransport(
1146 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001147 const cricket::ContentInfo& content_info,
1148 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001149 RTC_DCHECK(network_thread_->IsCurrent());
1150 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1151 if (transport) {
1152 return RTCError::OK();
1153 }
1154
1155 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001156 content_info.media_description();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001157 if (certificate_ && !content_desc->cryptos().empty()) {
1158 return RTCError(RTCErrorType::INVALID_PARAMETER,
1159 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1160 }
1161
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001162 std::unique_ptr<cricket::IceTransportInternal> ice =
1163 CreateIceTransport(content_info.name, /*rtcp=*/false);
1164
1165 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001166 MaybeCreateMediaTransport(content_info, description, local);
1167 if (media_transport) {
1168 media_transport_created_once_ = true;
1169 media_transport->Connect(ice.get());
1170 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001171
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001172 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1173 MaybeCreateDatagramTransport(content_info, description, local);
1174 if (datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001175 datagram_transport->Connect(ice.get());
1176 }
1177
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001178 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001179 CreateDtlsTransport(content_info, ice.get(), nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001180
1181 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1182 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1183 std::unique_ptr<SrtpTransport> sdes_transport;
1184 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001185 std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001186
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001187 std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001188 if (config_.rtcp_mux_policy !=
1189 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1190 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001191 RTC_DCHECK(media_transport == nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001192 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001193 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001194 rtcp_dtls_transport = CreateDtlsTransport(content_info, rtcp_ice.get(),
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001195 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001196 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001197
Bjorn A Mellem703ea952019-08-23 10:31:11 -07001198 // Only create a datagram RTP transport if the datagram transport should be
1199 // used for RTP.
1200 if (datagram_transport && config_.use_datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001201 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1202 // because MediaTransport encrypts. In the future we may want to
1203 // implement our own version of RtpTransport over MediaTransport, because
1204 // it will give us more control over things like:
1205 // - Fusing
1206 // - Rtp header compression
1207 // - Handling Rtcp feedback.
1208 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1209 "transport is used.";
1210 RTC_DCHECK(!rtcp_dtls_transport);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001211 datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001212 content_info.media_description()->rtp_header_extensions(), ice.get(),
1213 datagram_transport.get());
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001214 }
1215
1216 if (config_.disable_encryption) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001217 RTC_LOG(LS_INFO)
1218 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001219 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001220 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001221 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001222 sdes_transport = CreateSdesTransport(
1223 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001224 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001225 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001226 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001227 dtls_srtp_transport = CreateDtlsSrtpTransport(
1228 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001229 }
1230
Zhi Huang365381f2018-04-13 16:44:34 -07001231 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001232 std::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001233 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1234 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001235 std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
1236 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
Qingsi Wang437077d2019-09-10 17:52:26 +00001237 std::move(media_transport), std::move(datagram_transport));
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001238
Zhi Huange818b6e2018-02-22 15:26:27 -08001239 jsep_transport->SignalRtcpMuxActive.connect(
1240 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001241 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001242 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001243 jsep_transport->SignalDataChannelTransportNegotiated.connect(
1244 this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001245 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001246
Zhi Huangd2248f82018-04-10 14:41:03 -07001247 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1248 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001249 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001250}
1251
1252void JsepTransportController::MaybeDestroyJsepTransport(
1253 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001254 auto jsep_transport = GetJsepTransportByName(mid);
1255 if (!jsep_transport) {
1256 return;
1257 }
1258
1259 // Don't destroy the JsepTransport if there are still media sections referring
1260 // to it.
1261 for (const auto& kv : mid_to_transport_) {
1262 if (kv.second == jsep_transport) {
1263 return;
1264 }
1265 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001266
Zhi Huange830e682018-03-30 10:48:35 -07001267 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001268 UpdateAggregateStates_n();
1269}
1270
1271void JsepTransportController::DestroyAllJsepTransports_n() {
1272 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001273
1274 for (const auto& jsep_transport : jsep_transports_by_name_) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001275 config_.transport_observer->OnTransportChanged(
Qingsi Wang437077d2019-09-10 17:52:26 +00001276 jsep_transport.first, nullptr, nullptr, nullptr, nullptr,
1277 NegotiationState::kFinal);
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001278 }
1279
Zhi Huange830e682018-03-30 10:48:35 -07001280 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001281}
1282
1283void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1284 RTC_DCHECK(network_thread_->IsCurrent());
1285
1286 ice_role_ = ice_role;
1287 for (auto& dtls : GetDtlsTransports()) {
1288 dtls->ice_transport()->SetIceRole(ice_role_);
1289 }
1290}
1291
1292cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001293 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001294 const cricket::TransportInfo& transport_info,
1295 SdpType type,
1296 bool local) {
1297 cricket::IceRole ice_role = ice_role_;
1298 auto tdesc = transport_info.description;
1299 if (local) {
1300 // The initial offer side may use ICE Lite, in which case, per RFC5245
1301 // Section 5.1.1, the answer side should take the controlling role if it is
1302 // in the full ICE mode.
1303 //
1304 // When both sides use ICE Lite, the initial offer side must take the
1305 // controlling role, and this is the default logic implemented in
1306 // SetLocalDescription in JsepTransportController.
1307 if (jsep_transport->remote_description() &&
1308 jsep_transport->remote_description()->transport_desc.ice_mode ==
1309 cricket::ICEMODE_LITE &&
1310 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1311 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1312 ice_role = cricket::ICEROLE_CONTROLLING;
1313 }
1314
1315 // Older versions of Chrome expect the ICE role to be re-determined when an
1316 // ICE restart occurs, and also don't perform conflict resolution correctly,
1317 // so for now we can't safely stop doing this, unless the application opts
1318 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1319 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1320 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1321 // enough population.
1322 if (config_.redetermine_role_on_ice_restart &&
1323 jsep_transport->local_description() &&
1324 cricket::IceCredentialsChanged(
1325 jsep_transport->local_description()->transport_desc.ice_ufrag,
1326 jsep_transport->local_description()->transport_desc.ice_pwd,
1327 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1328 // Don't change the ICE role if the remote endpoint is ICE lite; we
1329 // should always be controlling in that case.
1330 (!jsep_transport->remote_description() ||
1331 jsep_transport->remote_description()->transport_desc.ice_mode !=
1332 cricket::ICEMODE_LITE)) {
1333 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1334 : cricket::ICEROLE_CONTROLLED;
1335 }
1336 } else {
1337 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1338 // supports only ice_lite, this local endpoint should take the CONTROLLING
1339 // role.
1340 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1341 // be in a TransportDescription in the first place...
1342 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1343 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1344 ice_role = cricket::ICEROLE_CONTROLLING;
1345 }
1346
1347 // If we use ICE Lite and the remote endpoint uses the full implementation
1348 // of ICE, the local endpoint must take the controlled role, and the other
1349 // side must be the controlling role.
1350 if (jsep_transport->local_description() &&
1351 jsep_transport->local_description()->transport_desc.ice_mode ==
1352 cricket::ICEMODE_LITE &&
1353 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001354 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001355 ice_role = cricket::ICEROLE_CONTROLLED;
1356 }
1357 }
1358
1359 return ice_role;
1360}
1361
1362void JsepTransportController::OnTransportWritableState_n(
1363 rtc::PacketTransportInternal* transport) {
1364 RTC_DCHECK(network_thread_->IsCurrent());
1365 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1366 << " writability changed to " << transport->writable()
1367 << ".";
1368 UpdateAggregateStates_n();
1369}
1370
1371void JsepTransportController::OnTransportReceivingState_n(
1372 rtc::PacketTransportInternal* transport) {
1373 RTC_DCHECK(network_thread_->IsCurrent());
1374 UpdateAggregateStates_n();
1375}
1376
1377void JsepTransportController::OnTransportGatheringState_n(
1378 cricket::IceTransportInternal* transport) {
1379 RTC_DCHECK(network_thread_->IsCurrent());
1380 UpdateAggregateStates_n();
1381}
1382
1383void JsepTransportController::OnTransportCandidateGathered_n(
1384 cricket::IceTransportInternal* transport,
1385 const cricket::Candidate& candidate) {
1386 RTC_DCHECK(network_thread_->IsCurrent());
1387
1388 // We should never signal peer-reflexive candidates.
1389 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1390 RTC_NOTREACHED();
1391 return;
1392 }
Steve Antond25828a2018-08-31 13:06:05 -07001393 std::string transport_name = transport->transport_name();
1394 invoker_.AsyncInvoke<void>(
1395 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1396 SignalIceCandidatesGathered(transport_name, {candidate});
1397 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001398}
1399
Eldar Relloda13ea22019-06-01 12:23:43 +03001400void JsepTransportController::OnTransportCandidateError_n(
1401 cricket::IceTransportInternal* transport,
1402 const cricket::IceCandidateErrorEvent& event) {
1403 RTC_DCHECK(network_thread_->IsCurrent());
1404
1405 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1406 [this, event] { SignalIceCandidateError(event); });
1407}
Zhi Huange818b6e2018-02-22 15:26:27 -08001408void JsepTransportController::OnTransportCandidatesRemoved_n(
1409 cricket::IceTransportInternal* transport,
1410 const cricket::Candidates& candidates) {
1411 invoker_.AsyncInvoke<void>(
1412 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001413 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001414}
Alex Drake00c7ecf2019-08-06 10:54:47 -07001415void JsepTransportController::OnTransportCandidatePairChanged_n(
1416 const cricket::CandidatePairChangeEvent& event) {
1417 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
1418 SignalIceCandidatePairChanged(event);
1419 });
1420}
Zhi Huange818b6e2018-02-22 15:26:27 -08001421
1422void JsepTransportController::OnTransportRoleConflict_n(
1423 cricket::IceTransportInternal* transport) {
1424 RTC_DCHECK(network_thread_->IsCurrent());
1425 // Note: since the role conflict is handled entirely on the network thread,
1426 // we don't need to worry about role conflicts occurring on two ports at
1427 // once. The first one encountered should immediately reverse the role.
1428 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1429 ? cricket::ICEROLE_CONTROLLED
1430 : cricket::ICEROLE_CONTROLLING;
1431 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1432 << (reversed_role == cricket::ICEROLE_CONTROLLING
1433 ? "controlling"
1434 : "controlled")
1435 << " role.";
1436 SetIceRole_n(reversed_role);
1437}
1438
1439void JsepTransportController::OnTransportStateChanged_n(
1440 cricket::IceTransportInternal* transport) {
1441 RTC_DCHECK(network_thread_->IsCurrent());
1442 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1443 << transport->component()
1444 << " state changed. Check if state is complete.";
1445 UpdateAggregateStates_n();
1446}
1447
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001448void JsepTransportController::OnMediaTransportStateChanged_n() {
1449 SignalMediaTransportStateChanged();
1450 UpdateAggregateStates_n();
1451}
1452
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001453void JsepTransportController::OnDataChannelTransportNegotiated_n(
1454 cricket::JsepTransport* transport,
Qingsi Wang437077d2019-09-10 17:52:26 +00001455 DataChannelTransportInterface* data_channel_transport,
1456 bool provisional) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001457 for (auto it : mid_to_transport_) {
1458 if (it.second == transport) {
1459 config_.transport_observer->OnTransportChanged(
1460 it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
Qingsi Wang437077d2019-09-10 17:52:26 +00001461 transport->media_transport(), data_channel_transport,
1462 provisional ? NegotiationState::kProvisional
1463 : NegotiationState::kFinal);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001464 }
1465 }
1466}
1467
Zhi Huange818b6e2018-02-22 15:26:27 -08001468void JsepTransportController::UpdateAggregateStates_n() {
1469 RTC_DCHECK(network_thread_->IsCurrent());
1470
1471 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001472 cricket::IceConnectionState new_connection_state =
1473 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001474 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1475 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1476 PeerConnectionInterface::PeerConnectionState new_combined_state =
1477 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001478 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001479 bool any_failed = false;
1480
1481 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1482 // dtls_transports entirely, the below line will have to be changed to account
1483 // for the fact that dtls transports might be absent.
1484 bool all_connected = !dtls_transports.empty();
1485 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001486 bool any_gathering = false;
1487 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001488
1489 std::map<IceTransportState, int> ice_state_counts;
1490 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1491
Zhi Huange818b6e2018-02-22 15:26:27 -08001492 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001493 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1494 cricket::IceTransportState::STATE_FAILED;
1495 all_connected = all_connected && dtls->writable();
1496 all_completed =
1497 all_completed && dtls->writable() &&
1498 dtls->ice_transport()->GetState() ==
1499 cricket::IceTransportState::STATE_COMPLETED &&
1500 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1501 dtls->ice_transport()->gathering_state() ==
1502 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001503 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1504 cricket::kIceGatheringNew;
1505 all_done_gathering =
1506 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1507 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001508
1509 dtls_state_counts[dtls->dtls_state()]++;
1510 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001511 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001512
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001513 // Don't indicate that the call failed or isn't connected due to media
1514 // transport state unless the media transport is used for media. If it's only
1515 // used for data channels, it will signal those separately.
1516 if (config_.use_media_transport_for_media || config_.use_datagram_transport) {
1517 for (auto it = jsep_transports_by_name_.begin();
1518 it != jsep_transports_by_name_.end(); ++it) {
1519 auto jsep_transport = it->second.get();
1520 if (!jsep_transport->media_transport()) {
1521 continue;
1522 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001523
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001524 // There is no 'kIceConnectionDisconnected', so we only need to handle
1525 // connected and completed.
1526 // We treat kClosed as failed, because if it happens before shutting down
1527 // media transports it means that there was a failure.
1528 // MediaTransportInterface allows to flip back and forth between kWritable
1529 // and kPending, but there does not exist an implementation that does
1530 // that, and the contract of jsep transport controller doesn't quite
1531 // expect that. When this happens, we would go from connected to
1532 // connecting state, but this may change in future.
1533 any_failed |= jsep_transport->media_transport_state() ==
1534 webrtc::MediaTransportState::kClosed;
1535 all_completed &= jsep_transport->media_transport_state() ==
1536 webrtc::MediaTransportState::kWritable;
1537 all_connected &= jsep_transport->media_transport_state() ==
1538 webrtc::MediaTransportState::kWritable;
1539 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001540 }
1541
1542 if (any_failed) {
1543 new_connection_state = cricket::kIceConnectionFailed;
1544 } else if (all_completed) {
1545 new_connection_state = cricket::kIceConnectionCompleted;
1546 } else if (all_connected) {
1547 new_connection_state = cricket::kIceConnectionConnected;
1548 }
1549 if (ice_connection_state_ != new_connection_state) {
1550 ice_connection_state_ = new_connection_state;
1551 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1552 [this, new_connection_state] {
1553 SignalIceConnectionState(new_connection_state);
1554 });
1555 }
1556
Jonas Olsson635474e2018-10-18 15:58:17 +02001557 // Compute the current RTCIceConnectionState as described in
1558 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1559 // The PeerConnection is responsible for handling the "closed" state.
1560 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1561 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1562 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1563 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1564 int total_ice_disconnected =
1565 ice_state_counts[IceTransportState::kDisconnected];
1566 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1567 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1568 int total_ice = dtls_transports.size();
1569
1570 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001571 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001572 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001573 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001574 // None of the previous states apply and any RTCIceTransports are in the
1575 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001576 new_ice_connection_state =
1577 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001578 } else if (total_ice_new + total_ice_closed == total_ice) {
1579 // None of the previous states apply and all RTCIceTransports are in the
1580 // "new" or "closed" state, or there are no transports.
1581 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1582 } else if (total_ice_new + total_ice_checking > 0) {
1583 // None of the previous states apply and any RTCIceTransports are in the
1584 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001585 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001586 } else if (total_ice_completed + total_ice_closed == total_ice ||
1587 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001588 // None of the previous states apply and all RTCIceTransports are in the
1589 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001590 //
1591 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1592 // to mimic the behavior of the old ICE connection state, and should be
1593 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001594 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1595 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001596 total_ice) {
1597 // None of the previous states apply and all RTCIceTransports are in the
1598 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001599 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001600 } else {
1601 RTC_NOTREACHED();
1602 }
1603
Alex Loiko9289eda2018-11-23 16:18:59 +00001604 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001605 if (standardized_ice_connection_state_ ==
1606 PeerConnectionInterface::kIceConnectionChecking &&
1607 new_ice_connection_state ==
1608 PeerConnectionInterface::kIceConnectionCompleted) {
1609 // Ensure that we never skip over the "connected" state.
1610 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1611 SignalStandardizedIceConnectionState(
1612 PeerConnectionInterface::kIceConnectionConnected);
1613 });
1614 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001615 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001616 invoker_.AsyncInvoke<void>(
1617 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001618 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001619 });
1620 }
1621
1622 // Compute the current RTCPeerConnectionState as described in
1623 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1624 // The PeerConnection is responsible for handling the "closed" state.
1625 // Note that "connecting" is only a valid state for DTLS transports while
1626 // "checking", "completed" and "disconnected" are only valid for ICE
1627 // transports.
1628 int total_connected = total_ice_connected +
1629 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1630 int total_dtls_connecting =
1631 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1632 int total_failed =
1633 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1634 int total_closed =
1635 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1636 int total_new =
1637 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1638 int total_transports = total_ice * 2;
1639
1640 if (total_failed > 0) {
1641 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1642 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001643 } else if (total_ice_disconnected > 0) {
1644 // None of the previous states apply and any RTCIceTransports or
1645 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001646 new_combined_state =
1647 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001648 } else if (total_new + total_closed == total_transports) {
1649 // None of the previous states apply and all RTCIceTransports and
1650 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1651 // transports.
1652 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1653 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1654 // None of the previous states apply and all RTCIceTransports or
1655 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001656 new_combined_state =
1657 PeerConnectionInterface::PeerConnectionState::kConnecting;
1658 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001659 total_transports) {
1660 // None of the previous states apply and all RTCIceTransports and
1661 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001662 new_combined_state =
1663 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001664 } else {
1665 RTC_NOTREACHED();
1666 }
1667
1668 if (combined_connection_state_ != new_combined_state) {
1669 combined_connection_state_ = new_combined_state;
1670 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1671 [this, new_combined_state] {
1672 SignalConnectionState(new_combined_state);
1673 });
1674 }
1675
Zhi Huange818b6e2018-02-22 15:26:27 -08001676 if (all_done_gathering) {
1677 new_gathering_state = cricket::kIceGatheringComplete;
1678 } else if (any_gathering) {
1679 new_gathering_state = cricket::kIceGatheringGathering;
1680 }
1681 if (ice_gathering_state_ != new_gathering_state) {
1682 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001683 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1684 [this, new_gathering_state] {
1685 SignalIceGatheringState(new_gathering_state);
1686 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001687 }
1688}
1689
1690void JsepTransportController::OnDtlsHandshakeError(
1691 rtc::SSLHandshakeError error) {
1692 SignalDtlsHandshakeError(error);
1693}
1694
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001695absl::optional<cricket::SessionDescription::MediaTransportSetting>
1696JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001697 if (media_transport_created_once_) {
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001698 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1699 "existing session.";
1700 return media_transport_offer_settings_;
1701 }
1702
1703 RTC_LOG(LS_INFO) << "Generating media transport offer!";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001704
1705 absl::optional<std::string> transport_parameters;
1706
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001707 // Check that media transport is supposed to be used.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001708 // Note that ICE is not available when media transport is created. It will
1709 // only be available in 'Connect'. This may be a potential server config, if
1710 // we decide to use this peer connection as a caller, not as a callee.
1711 // TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001712 if (config_.use_media_transport_for_media ||
1713 config_.use_media_transport_for_data_channels) {
1714 RTC_DCHECK(config_.media_transport_factory != nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001715 RTC_DCHECK(!config_.use_datagram_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001716 webrtc::MediaTransportSettings settings;
1717 settings.is_caller = true;
1718 settings.pre_shared_key = rtc::CreateRandomString(32);
Bjorn A Mellemb073f1c2019-07-02 09:50:35 -07001719 if (config_.use_media_transport_for_media) {
1720 settings.event_log = config_.event_log;
1721 }
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001722 auto media_transport_or_error =
1723 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1724 settings);
1725
1726 if (media_transport_or_error.ok()) {
1727 offer_media_transport_ = std::move(media_transport_or_error.value());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001728 transport_parameters =
1729 offer_media_transport_->GetTransportParametersOffer();
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001730 } else {
1731 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1732 << media_transport_or_error.error().message();
1733 }
1734 }
1735
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001736 if (!offer_media_transport_) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001737 RTC_LOG(LS_INFO) << "Media and data transports do not exist";
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001738 return absl::nullopt;
1739 }
1740
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001741 if (!transport_parameters) {
1742 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1743 // Media transport didn't generate the offer, and is not supposed to be
1744 // used. Destroy the temporary media transport.
1745 offer_media_transport_ = nullptr;
1746 return absl::nullopt;
1747 }
1748
1749 cricket::SessionDescription::MediaTransportSetting setting;
1750 setting.transport_name = config_.media_transport_factory->GetTransportName();
1751 setting.transport_setting = *transport_parameters;
1752 media_transport_offer_settings_ = setting;
1753 return setting;
1754}
1755
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001756absl::optional<cricket::OpaqueTransportParameters>
1757JsepTransportController::GetTransportParameters(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001758 if (!(config_.use_datagram_transport ||
1759 config_.use_datagram_transport_for_data_channels)) {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001760 return absl::nullopt;
1761 }
1762
1763 cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
1764 if (transport) {
1765 absl::optional<cricket::OpaqueTransportParameters> params =
1766 transport->GetTransportParameters();
1767 if (params) {
1768 params->protocol = config_.media_transport_factory->GetTransportName();
1769 }
1770 return params;
1771 }
1772
1773 RTC_DCHECK(!local_desc_ && !remote_desc_)
1774 << "JsepTransport should exist for every mid once any description is set";
1775
1776 // Need to generate a transport for the offer.
1777 if (!offer_datagram_transport_) {
1778 webrtc::MediaTransportSettings settings;
1779 settings.is_caller = true;
1780 settings.pre_shared_key = rtc::CreateRandomString(32);
1781 settings.event_log = config_.event_log;
1782 auto datagram_transport_or_error =
1783 config_.media_transport_factory->CreateDatagramTransport(
1784 network_thread_, settings);
1785
1786 if (datagram_transport_or_error.ok()) {
1787 offer_datagram_transport_ =
1788 std::move(datagram_transport_or_error.value());
1789 } else {
1790 RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
1791 << datagram_transport_or_error.error().message();
1792 }
1793 }
1794
1795 // We have prepared a transport for the offer, and can now use its parameters.
1796 cricket::OpaqueTransportParameters params;
1797 params.parameters = offer_datagram_transport_->GetTransportParameters();
1798 params.protocol = config_.media_transport_factory->GetTransportName();
1799 return params;
1800}
1801
Zhi Huange818b6e2018-02-22 15:26:27 -08001802} // namespace webrtc