blob: c9ff0a7dce0452ce5afd8c32f0a5b9aa4d339d3c [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);
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +020092 RTC_DCHECK(config_.rtcp_handler);
Zhi Huang365381f2018-04-13 16:44:34 -070093}
Zhi Huange818b6e2018-02-22 15:26:27 -080094
95JsepTransportController::~JsepTransportController() {
96 // Channel destructors may try to send packets, so this needs to happen on
97 // the network thread.
98 network_thread_->Invoke<void>(
99 RTC_FROM_HERE,
100 rtc::Bind(&JsepTransportController::DestroyAllJsepTransports_n, this));
101}
102
103RTCError JsepTransportController::SetLocalDescription(
104 SdpType type,
105 const cricket::SessionDescription* description) {
106 if (!network_thread_->IsCurrent()) {
107 return network_thread_->Invoke<RTCError>(
108 RTC_FROM_HERE, [=] { return SetLocalDescription(type, description); });
109 }
110
111 if (!initial_offerer_.has_value()) {
112 initial_offerer_.emplace(type == SdpType::kOffer);
113 if (*initial_offerer_) {
114 SetIceRole_n(cricket::ICEROLE_CONTROLLING);
115 } else {
116 SetIceRole_n(cricket::ICEROLE_CONTROLLED);
117 }
118 }
119 return ApplyDescription_n(/*local=*/true, type, description);
120}
121
122RTCError JsepTransportController::SetRemoteDescription(
123 SdpType type,
124 const cricket::SessionDescription* description) {
125 if (!network_thread_->IsCurrent()) {
126 return network_thread_->Invoke<RTCError>(
127 RTC_FROM_HERE, [=] { return SetRemoteDescription(type, description); });
128 }
129
130 return ApplyDescription_n(/*local=*/false, type, description);
131}
132
133RtpTransportInternal* JsepTransportController::GetRtpTransport(
134 const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700135 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800136 if (!jsep_transport) {
137 return nullptr;
138 }
139 return jsep_transport->rtp_transport();
140}
141
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700142MediaTransportConfig JsepTransportController::GetMediaTransportConfig(
Anton Sukhanov7940da02018-10-10 10:34:49 -0700143 const std::string& mid) const {
144 auto jsep_transport = GetJsepTransportForMid(mid);
145 if (!jsep_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700146 return MediaTransportConfig();
147 }
148
149 MediaTransportInterface* media_transport = nullptr;
150 if (config_.use_media_transport_for_media) {
151 media_transport = jsep_transport->media_transport();
152 }
153
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700154 DatagramTransportInterface* datagram_transport = nullptr;
155 if (config_.use_datagram_transport) {
156 datagram_transport = jsep_transport->datagram_transport();
157 }
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700158
159 // Media transport and datagram transports can not be used together.
160 RTC_DCHECK(!media_transport || !datagram_transport);
161
162 if (media_transport) {
163 return MediaTransportConfig(media_transport);
164 } else if (datagram_transport) {
165 return MediaTransportConfig(
166 /*rtp_max_packet_size=*/datagram_transport->GetLargestDatagramSize());
167 } else {
168 return MediaTransportConfig();
169 }
170}
171
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700172DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700173 const std::string& mid) const {
174 auto jsep_transport = GetJsepTransportForMid(mid);
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700175 if (!jsep_transport) {
Anton Sukhanov7940da02018-10-10 10:34:49 -0700176 return nullptr;
177 }
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700178 return jsep_transport->data_channel_transport();
Anton Sukhanov7940da02018-10-10 10:34:49 -0700179}
180
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800181MediaTransportState JsepTransportController::GetMediaTransportState(
182 const std::string& mid) const {
183 auto jsep_transport = GetJsepTransportForMid(mid);
184 if (!jsep_transport) {
185 return MediaTransportState::kPending;
186 }
187 return jsep_transport->media_transport_state();
188}
189
Zhi Huange818b6e2018-02-22 15:26:27 -0800190cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
Harald Alvestrandad88c882018-11-28 16:47:46 +0100191 const std::string& mid) {
Zhi Huange830e682018-03-30 10:48:35 -0700192 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800193 if (!jsep_transport) {
194 return nullptr;
195 }
196 return jsep_transport->rtp_dtls_transport();
197}
198
Harald Alvestrandad88c882018-11-28 16:47:46 +0100199const cricket::DtlsTransportInternal*
200JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
Zhi Huange830e682018-03-30 10:48:35 -0700201 auto jsep_transport = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800202 if (!jsep_transport) {
203 return nullptr;
204 }
205 return jsep_transport->rtcp_dtls_transport();
206}
207
Harald Alvestrand4a7b3ac2019-01-17 10:39:40 +0100208rtc::scoped_refptr<webrtc::DtlsTransport>
Harald Alvestrandad88c882018-11-28 16:47:46 +0100209JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
210 auto jsep_transport = GetJsepTransportForMid(mid);
211 if (!jsep_transport) {
212 return nullptr;
213 }
214 return jsep_transport->RtpDtlsTransport();
215}
216
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700217rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
218 const std::string& mid) const {
219 auto jsep_transport = GetJsepTransportForMid(mid);
220 if (!jsep_transport) {
221 return nullptr;
222 }
223 return jsep_transport->SctpTransport();
224}
225
Zhi Huange818b6e2018-02-22 15:26:27 -0800226void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
227 if (!network_thread_->IsCurrent()) {
228 network_thread_->Invoke<void>(RTC_FROM_HERE, [&] { SetIceConfig(config); });
229 return;
230 }
231
232 ice_config_ = config;
233 for (auto& dtls : GetDtlsTransports()) {
234 dtls->ice_transport()->SetIceConfig(ice_config_);
235 }
236}
237
238void JsepTransportController::SetNeedsIceRestartFlag() {
Zhi Huange830e682018-03-30 10:48:35 -0700239 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800240 kv.second->SetNeedsIceRestartFlag();
241 }
242}
243
244bool JsepTransportController::NeedsIceRestart(
245 const std::string& transport_name) const {
Zhi Huang365381f2018-04-13 16:44:34 -0700246 const cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700247 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800248 if (!transport) {
249 return false;
250 }
251 return transport->needs_ice_restart();
252}
253
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200254absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
Zhi Huange830e682018-03-30 10:48:35 -0700255 const std::string& mid) const {
Zhi Huange818b6e2018-02-22 15:26:27 -0800256 if (!network_thread_->IsCurrent()) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200257 return network_thread_->Invoke<absl::optional<rtc::SSLRole>>(
Zhi Huange830e682018-03-30 10:48:35 -0700258 RTC_FROM_HERE, [&] { return GetDtlsRole(mid); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800259 }
260
Zhi Huang365381f2018-04-13 16:44:34 -0700261 const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -0800262 if (!t) {
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200263 return absl::optional<rtc::SSLRole>();
Zhi Huange818b6e2018-02-22 15:26:27 -0800264 }
265 return t->GetDtlsRole();
266}
267
268bool JsepTransportController::SetLocalCertificate(
269 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
270 if (!network_thread_->IsCurrent()) {
271 return network_thread_->Invoke<bool>(
272 RTC_FROM_HERE, [&] { return SetLocalCertificate(certificate); });
273 }
274
275 // Can't change a certificate, or set a null certificate.
276 if (certificate_ || !certificate) {
277 return false;
278 }
279 certificate_ = certificate;
280
281 // Set certificate for JsepTransport, which verifies it matches the
282 // fingerprint in SDP, and DTLS transport.
283 // Fallback from DTLS to SDES is not supported.
Zhi Huange830e682018-03-30 10:48:35 -0700284 for (auto& kv : jsep_transports_by_name_) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800285 kv.second->SetLocalCertificate(certificate_);
286 }
287 for (auto& dtls : GetDtlsTransports()) {
288 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
289 RTC_DCHECK(set_cert_success);
290 }
291 return true;
292}
293
294rtc::scoped_refptr<rtc::RTCCertificate>
295JsepTransportController::GetLocalCertificate(
296 const std::string& transport_name) const {
297 if (!network_thread_->IsCurrent()) {
298 return network_thread_->Invoke<rtc::scoped_refptr<rtc::RTCCertificate>>(
299 RTC_FROM_HERE, [&] { return GetLocalCertificate(transport_name); });
300 }
301
Zhi Huang365381f2018-04-13 16:44:34 -0700302 const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800303 if (!t) {
304 return nullptr;
305 }
306 return t->GetLocalCertificate();
307}
308
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800309std::unique_ptr<rtc::SSLCertChain>
310JsepTransportController::GetRemoteSSLCertChain(
Zhi Huange818b6e2018-02-22 15:26:27 -0800311 const std::string& transport_name) const {
312 if (!network_thread_->IsCurrent()) {
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800313 return network_thread_->Invoke<std::unique_ptr<rtc::SSLCertChain>>(
314 RTC_FROM_HERE, [&] { return GetRemoteSSLCertChain(transport_name); });
Zhi Huange818b6e2018-02-22 15:26:27 -0800315 }
316
Zhi Huange830e682018-03-30 10:48:35 -0700317 // Get the certificate from the RTP transport's DTLS handshake. Should be
318 // identical to the RTCP transport's, since they were given the same remote
Zhi Huange818b6e2018-02-22 15:26:27 -0800319 // fingerprint.
Zhi Huange830e682018-03-30 10:48:35 -0700320 auto jsep_transport = GetJsepTransportByName(transport_name);
321 if (!jsep_transport) {
322 return nullptr;
323 }
324 auto dtls = jsep_transport->rtp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800325 if (!dtls) {
326 return nullptr;
327 }
328
Taylor Brandstetterc3928662018-02-23 13:04:51 -0800329 return dtls->GetRemoteSSLCertChain();
Zhi Huange818b6e2018-02-22 15:26:27 -0800330}
331
332void JsepTransportController::MaybeStartGathering() {
333 if (!network_thread_->IsCurrent()) {
334 network_thread_->Invoke<void>(RTC_FROM_HERE,
335 [&] { MaybeStartGathering(); });
336 return;
337 }
338
339 for (auto& dtls : GetDtlsTransports()) {
340 dtls->ice_transport()->MaybeStartGathering();
341 }
342}
343
344RTCError JsepTransportController::AddRemoteCandidates(
345 const std::string& transport_name,
346 const cricket::Candidates& candidates) {
347 if (!network_thread_->IsCurrent()) {
348 return network_thread_->Invoke<RTCError>(RTC_FROM_HERE, [&] {
349 return AddRemoteCandidates(transport_name, candidates);
350 });
351 }
352
353 // Verify each candidate before passing down to the transport layer.
354 RTCError error = VerifyCandidates(candidates);
355 if (!error.ok()) {
356 return error;
357 }
Zhi Huange830e682018-03-30 10:48:35 -0700358 auto jsep_transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800359 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700360 RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
361 "doesn't exist. Ignore it.";
362 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -0800363 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800364 return jsep_transport->AddRemoteCandidates(candidates);
365}
366
367RTCError JsepTransportController::RemoveRemoteCandidates(
368 const cricket::Candidates& candidates) {
369 if (!network_thread_->IsCurrent()) {
370 return network_thread_->Invoke<RTCError>(
371 RTC_FROM_HERE, [&] { return RemoveRemoteCandidates(candidates); });
372 }
373
374 // Verify each candidate before passing down to the transport layer.
375 RTCError error = VerifyCandidates(candidates);
376 if (!error.ok()) {
377 return error;
378 }
379
380 std::map<std::string, cricket::Candidates> candidates_by_transport_name;
381 for (const cricket::Candidate& cand : candidates) {
382 if (!cand.transport_name().empty()) {
383 candidates_by_transport_name[cand.transport_name()].push_back(cand);
384 } else {
385 RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
386 "transport name set: "
Qingsi Wang20232a92019-09-06 12:51:17 -0700387 << cand.ToSensitiveString();
Zhi Huange818b6e2018-02-22 15:26:27 -0800388 }
389 }
390
391 for (const auto& kv : candidates_by_transport_name) {
392 const std::string& transport_name = kv.first;
393 const cricket::Candidates& candidates = kv.second;
Zhi Huang365381f2018-04-13 16:44:34 -0700394 cricket::JsepTransport* jsep_transport =
Zhi Huange830e682018-03-30 10:48:35 -0700395 GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800396 if (!jsep_transport) {
Zhi Huange830e682018-03-30 10:48:35 -0700397 RTC_LOG(LS_WARNING)
398 << "Not removing candidate because the JsepTransport doesn't exist.";
399 continue;
Zhi Huange818b6e2018-02-22 15:26:27 -0800400 }
401 for (const cricket::Candidate& candidate : candidates) {
Harald Alvestrandad88c882018-11-28 16:47:46 +0100402 cricket::DtlsTransportInternal* dtls =
403 candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
404 ? jsep_transport->rtp_dtls_transport()
405 : jsep_transport->rtcp_dtls_transport();
Zhi Huange818b6e2018-02-22 15:26:27 -0800406 if (dtls) {
407 dtls->ice_transport()->RemoveRemoteCandidate(candidate);
408 }
409 }
410 }
411 return RTCError::OK();
412}
413
414bool JsepTransportController::GetStats(const std::string& transport_name,
415 cricket::TransportStats* stats) {
416 if (!network_thread_->IsCurrent()) {
417 return network_thread_->Invoke<bool>(
418 RTC_FROM_HERE, [=] { return GetStats(transport_name, stats); });
419 }
420
Zhi Huang365381f2018-04-13 16:44:34 -0700421 cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800422 if (!transport) {
423 return false;
424 }
425 return transport->GetStats(stats);
426}
427
Zhi Huangb57e1692018-06-12 11:41:11 -0700428void JsepTransportController::SetActiveResetSrtpParams(
429 bool active_reset_srtp_params) {
430 if (!network_thread_->IsCurrent()) {
431 network_thread_->Invoke<void>(RTC_FROM_HERE, [=] {
432 SetActiveResetSrtpParams(active_reset_srtp_params);
433 });
434 return;
435 }
436
437 RTC_LOG(INFO)
438 << "Updating the active_reset_srtp_params for JsepTransportController: "
439 << active_reset_srtp_params;
440 config_.active_reset_srtp_params = active_reset_srtp_params;
441 for (auto& kv : jsep_transports_by_name_) {
442 kv.second->SetActiveResetSrtpParams(active_reset_srtp_params);
443 }
444}
445
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800446void JsepTransportController::SetMediaTransportSettings(
447 bool use_media_transport_for_media,
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700448 bool use_media_transport_for_data_channels,
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700449 bool use_datagram_transport,
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700450 bool use_datagram_transport_for_data_channels,
451 bool use_datagram_transport_for_data_channels_receive_only) {
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800452 RTC_DCHECK(use_media_transport_for_media ==
453 config_.use_media_transport_for_media ||
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700454 jsep_transports_by_name_.empty())
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -0800455 << "You can only change media transport configuration before creating "
456 "the first transport.";
457
458 RTC_DCHECK(use_media_transport_for_data_channels ==
459 config_.use_media_transport_for_data_channels ||
460 jsep_transports_by_name_.empty())
461 << "You can only change media transport configuration before creating "
462 "the first transport.";
463
464 config_.use_media_transport_for_media = use_media_transport_for_media;
465 config_.use_media_transport_for_data_channels =
466 use_media_transport_for_data_channels;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700467 config_.use_datagram_transport = use_datagram_transport;
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700468 config_.use_datagram_transport_for_data_channels =
469 use_datagram_transport_for_data_channels;
Bjorn A Mellem7da4e562019-09-26 11:02:11 -0700470 config_.use_datagram_transport_for_data_channels_receive_only =
471 use_datagram_transport_for_data_channels_receive_only;
Piotr (Peter) Slatala97fc11f2018-10-18 12:57:59 -0700472}
473
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800474std::unique_ptr<cricket::IceTransportInternal>
475JsepTransportController::CreateIceTransport(const std::string transport_name,
476 bool rtcp) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800477 int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
478 : cricket::ICE_CANDIDATE_COMPONENT_RTP;
479
Zhi Huange818b6e2018-02-22 15:26:27 -0800480 if (config_.external_transport_factory) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800481 return config_.external_transport_factory->CreateIceTransport(
Zhi Huange818b6e2018-02-22 15:26:27 -0800482 transport_name, component);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800483 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200484 return std::make_unique<cricket::P2PTransportChannel>(
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800485 transport_name, component, port_allocator_, async_resolver_factory_,
486 config_.event_log);
487 }
488}
489
490std::unique_ptr<cricket::DtlsTransportInternal>
491JsepTransportController::CreateDtlsTransport(
Anton Sukhanovac6c0962019-07-10 15:44:56 -0700492 const cricket::ContentInfo& content_info,
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700493 cricket::IceTransportInternal* ice,
Anton Sukhanov292ce4e2019-06-03 13:00:24 -0700494 DatagramTransportInterface* datagram_transport) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800495 RTC_DCHECK(network_thread_->IsCurrent());
496
497 std::unique_ptr<cricket::DtlsTransportInternal> dtls;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700498
499 if (datagram_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700500 RTC_DCHECK(config_.use_datagram_transport ||
501 config_.use_datagram_transport_for_data_channels);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -0700502 } else if (config_.media_transport_factory &&
503 config_.use_media_transport_for_media &&
504 config_.use_media_transport_for_data_channels) {
505 // If media transport is used for both media and data channels,
506 // then we don't need to create DTLS.
507 // Otherwise, DTLS is still created.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200508 dtls = std::make_unique<cricket::NoOpDtlsTransport>(ice,
509 config_.crypto_options);
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -0800510 } else if (config_.external_transport_factory) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800511 dtls = config_.external_transport_factory->CreateDtlsTransport(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -0700512 ice, config_.crypto_options);
Zhi Huange818b6e2018-02-22 15:26:27 -0800513 } else {
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200514 dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
515 config_.event_log);
Zhi Huange818b6e2018-02-22 15:26:27 -0800516 }
517
518 RTC_DCHECK(dtls);
519 dtls->SetSslMaxProtocolVersion(config_.ssl_max_version);
Zhi Huange818b6e2018-02-22 15:26:27 -0800520 dtls->ice_transport()->SetIceRole(ice_role_);
521 dtls->ice_transport()->SetIceTiebreaker(ice_tiebreaker_);
522 dtls->ice_transport()->SetIceConfig(ice_config_);
523 if (certificate_) {
524 bool set_cert_success = dtls->SetLocalCertificate(certificate_);
525 RTC_DCHECK(set_cert_success);
526 }
527
528 // Connect to signals offered by the DTLS and ICE transport.
529 dtls->SignalWritableState.connect(
530 this, &JsepTransportController::OnTransportWritableState_n);
531 dtls->SignalReceivingState.connect(
532 this, &JsepTransportController::OnTransportReceivingState_n);
533 dtls->SignalDtlsHandshakeError.connect(
534 this, &JsepTransportController::OnDtlsHandshakeError);
535 dtls->ice_transport()->SignalGatheringState.connect(
536 this, &JsepTransportController::OnTransportGatheringState_n);
537 dtls->ice_transport()->SignalCandidateGathered.connect(
538 this, &JsepTransportController::OnTransportCandidateGathered_n);
Eldar Relloda13ea22019-06-01 12:23:43 +0300539 dtls->ice_transport()->SignalCandidateError.connect(
540 this, &JsepTransportController::OnTransportCandidateError_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800541 dtls->ice_transport()->SignalCandidatesRemoved.connect(
542 this, &JsepTransportController::OnTransportCandidatesRemoved_n);
543 dtls->ice_transport()->SignalRoleConflict.connect(
544 this, &JsepTransportController::OnTransportRoleConflict_n);
545 dtls->ice_transport()->SignalStateChanged.connect(
546 this, &JsepTransportController::OnTransportStateChanged_n);
Jonas Olsson7a6739e2019-01-15 16:31:55 +0100547 dtls->ice_transport()->SignalIceTransportStateChanged.connect(
548 this, &JsepTransportController::OnTransportStateChanged_n);
Alex Drake00c7ecf2019-08-06 10:54:47 -0700549 dtls->ice_transport()->SignalCandidatePairChanged.connect(
550 this, &JsepTransportController::OnTransportCandidatePairChanged_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800551 return dtls;
552}
553
554std::unique_ptr<webrtc::RtpTransport>
555JsepTransportController::CreateUnencryptedRtpTransport(
556 const std::string& transport_name,
557 rtc::PacketTransportInternal* rtp_packet_transport,
558 rtc::PacketTransportInternal* rtcp_packet_transport) {
559 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange830e682018-03-30 10:48:35 -0700560 auto unencrypted_rtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200561 std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700562 unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
563 if (rtcp_packet_transport) {
564 unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
565 }
566 return unencrypted_rtp_transport;
Zhi Huange818b6e2018-02-22 15:26:27 -0800567}
568
569std::unique_ptr<webrtc::SrtpTransport>
570JsepTransportController::CreateSdesTransport(
571 const std::string& transport_name,
Zhi Huange830e682018-03-30 10:48:35 -0700572 cricket::DtlsTransportInternal* rtp_dtls_transport,
573 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800574 RTC_DCHECK(network_thread_->IsCurrent());
Zhi Huange818b6e2018-02-22 15:26:27 -0800575 auto srtp_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200576 std::make_unique<webrtc::SrtpTransport>(rtcp_dtls_transport == nullptr);
Zhi Huange830e682018-03-30 10:48:35 -0700577 RTC_DCHECK(rtp_dtls_transport);
578 srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
579 if (rtcp_dtls_transport) {
580 srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800581 }
582 if (config_.enable_external_auth) {
583 srtp_transport->EnableExternalAuth();
584 }
585 return srtp_transport;
586}
587
588std::unique_ptr<webrtc::DtlsSrtpTransport>
589JsepTransportController::CreateDtlsSrtpTransport(
590 const std::string& transport_name,
591 cricket::DtlsTransportInternal* rtp_dtls_transport,
592 cricket::DtlsTransportInternal* rtcp_dtls_transport) {
593 RTC_DCHECK(network_thread_->IsCurrent());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200594 auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
Zhi Huang365381f2018-04-13 16:44:34 -0700595 rtcp_dtls_transport == nullptr);
Zhi Huang27f3bf52018-03-26 21:37:23 -0700596 if (config_.enable_external_auth) {
Zhi Huang365381f2018-04-13 16:44:34 -0700597 dtls_srtp_transport->EnableExternalAuth();
Zhi Huang27f3bf52018-03-26 21:37:23 -0700598 }
Zhi Huang97d5e5b2018-03-27 00:09:01 +0000599
Zhi Huange818b6e2018-02-22 15:26:27 -0800600 dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
601 rtcp_dtls_transport);
Zhi Huangb57e1692018-06-12 11:41:11 -0700602 dtls_srtp_transport->SetActiveResetSrtpParams(
603 config_.active_reset_srtp_params);
Jonas Olsson635474e2018-10-18 15:58:17 +0200604 dtls_srtp_transport->SignalDtlsStateChange.connect(
605 this, &JsepTransportController::UpdateAggregateStates_n);
Zhi Huange818b6e2018-02-22 15:26:27 -0800606 return dtls_srtp_transport;
607}
608
609std::vector<cricket::DtlsTransportInternal*>
610JsepTransportController::GetDtlsTransports() {
611 std::vector<cricket::DtlsTransportInternal*> dtls_transports;
Zhi Huange830e682018-03-30 10:48:35 -0700612 for (auto it = jsep_transports_by_name_.begin();
613 it != jsep_transports_by_name_.end(); ++it) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800614 auto jsep_transport = it->second.get();
615 RTC_DCHECK(jsep_transport);
616 if (jsep_transport->rtp_dtls_transport()) {
617 dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
618 }
619
620 if (jsep_transport->rtcp_dtls_transport()) {
621 dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
622 }
623 }
624 return dtls_transports;
625}
626
Zhi Huange818b6e2018-02-22 15:26:27 -0800627RTCError JsepTransportController::ApplyDescription_n(
628 bool local,
629 SdpType type,
630 const cricket::SessionDescription* description) {
631 RTC_DCHECK(network_thread_->IsCurrent());
632 RTC_DCHECK(description);
633
634 if (local) {
635 local_desc_ = description;
636 } else {
637 remote_desc_ = description;
638 }
639
Zhi Huange830e682018-03-30 10:48:35 -0700640 RTCError error;
Zhi Huangd2248f82018-04-10 14:41:03 -0700641 error = ValidateAndMaybeUpdateBundleGroup(local, type, description);
Zhi Huange830e682018-03-30 10:48:35 -0700642 if (!error.ok()) {
643 return error;
Zhi Huange818b6e2018-02-22 15:26:27 -0800644 }
645
646 std::vector<int> merged_encrypted_extension_ids;
647 if (bundle_group_) {
648 merged_encrypted_extension_ids =
649 MergeEncryptedHeaderExtensionIdsForBundle(description);
650 }
651
652 for (const cricket::ContentInfo& content_info : description->contents()) {
653 // Don't create transports for rejected m-lines and bundled m-lines."
654 if (content_info.rejected ||
655 (IsBundled(content_info.name) && content_info.name != *bundled_mid())) {
656 continue;
657 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -0800658 error = MaybeCreateJsepTransport(local, content_info, *description);
Zhi Huange830e682018-03-30 10:48:35 -0700659 if (!error.ok()) {
660 return error;
661 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800662 }
663
664 RTC_DCHECK(description->contents().size() ==
665 description->transport_infos().size());
666 for (size_t i = 0; i < description->contents().size(); ++i) {
667 const cricket::ContentInfo& content_info = description->contents()[i];
668 const cricket::TransportInfo& transport_info =
669 description->transport_infos()[i];
670 if (content_info.rejected) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700671 HandleRejectedContent(content_info, description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800672 continue;
673 }
674
675 if (IsBundled(content_info.name) && content_info.name != *bundled_mid()) {
Zhi Huang365381f2018-04-13 16:44:34 -0700676 if (!HandleBundledContent(content_info)) {
677 return RTCError(RTCErrorType::INVALID_PARAMETER,
678 "Failed to process the bundled m= section.");
679 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800680 continue;
681 }
682
Zhi Huange830e682018-03-30 10:48:35 -0700683 error = ValidateContent(content_info);
684 if (!error.ok()) {
685 return error;
686 }
687
Zhi Huange818b6e2018-02-22 15:26:27 -0800688 std::vector<int> extension_ids;
Taylor Brandstetter0ab56512018-04-12 10:30:48 -0700689 if (bundled_mid() && content_info.name == *bundled_mid()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800690 extension_ids = merged_encrypted_extension_ids;
691 } else {
692 extension_ids = GetEncryptedHeaderExtensionIds(content_info);
693 }
694
Zhi Huange830e682018-03-30 10:48:35 -0700695 int rtp_abs_sendtime_extn_id =
696 GetRtpAbsSendTimeHeaderExtensionId(content_info);
697
Zhi Huang365381f2018-04-13 16:44:34 -0700698 cricket::JsepTransport* transport =
Zhi Huange830e682018-03-30 10:48:35 -0700699 GetJsepTransportForMid(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800700 RTC_DCHECK(transport);
701
702 SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
703
Zhi Huange818b6e2018-02-22 15:26:27 -0800704 cricket::JsepTransportDescription jsep_description =
705 CreateJsepTransportDescription(content_info, transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700706 extension_ids, rtp_abs_sendtime_extn_id);
Zhi Huange818b6e2018-02-22 15:26:27 -0800707 if (local) {
708 error =
709 transport->SetLocalJsepTransportDescription(jsep_description, type);
710 } else {
711 error =
712 transport->SetRemoteJsepTransportDescription(jsep_description, type);
713 }
714
715 if (!error.ok()) {
716 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
717 "Failed to apply the description for " +
718 content_info.name + ": " + error.message());
719 }
720 }
721 return RTCError::OK();
722}
723
Zhi Huangd2248f82018-04-10 14:41:03 -0700724RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroup(
725 bool local,
726 SdpType type,
Zhi Huange830e682018-03-30 10:48:35 -0700727 const cricket::SessionDescription* description) {
728 RTC_DCHECK(description);
Zhi Huangd2248f82018-04-10 14:41:03 -0700729 const cricket::ContentGroup* new_bundle_group =
730 description->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
731
732 // The BUNDLE group containing a MID that no m= section has is invalid.
733 if (new_bundle_group) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100734 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700735 if (!description->GetContentByName(content_name)) {
736 return RTCError(RTCErrorType::INVALID_PARAMETER,
737 "The BUNDLE group contains MID:" + content_name +
738 " matching no m= section.");
739 }
740 }
741 }
742
743 if (type == SdpType::kAnswer) {
744 const cricket::ContentGroup* offered_bundle_group =
745 local ? remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE)
746 : local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
747
748 if (new_bundle_group) {
749 // The BUNDLE group in answer should be a subset of offered group.
Mirko Bonadei739baf02019-01-27 17:29:42 +0100750 for (const auto& content_name : new_bundle_group->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700751 if (!offered_bundle_group ||
752 !offered_bundle_group->HasContentName(content_name)) {
753 return RTCError(RTCErrorType::INVALID_PARAMETER,
754 "The BUNDLE group in answer contains a MID that was "
755 "not in the offered group.");
756 }
757 }
758 }
759
760 if (bundle_group_) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100761 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700762 // An answer that removes m= sections from pre-negotiated BUNDLE group
763 // without rejecting it, is invalid.
764 if (!new_bundle_group ||
765 !new_bundle_group->HasContentName(content_name)) {
766 auto* content_info = description->GetContentByName(content_name);
767 if (!content_info || !content_info->rejected) {
768 return RTCError(RTCErrorType::INVALID_PARAMETER,
769 "Answer cannot remove m= section " + content_name +
770 " from already-established BUNDLE group.");
771 }
772 }
773 }
774 }
775 }
776
777 if (config_.bundle_policy ==
778 PeerConnectionInterface::kBundlePolicyMaxBundle &&
779 !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
780 return RTCError(RTCErrorType::INVALID_PARAMETER,
781 "max-bundle is used but no bundle group found.");
782 }
783
784 if (ShouldUpdateBundleGroup(type, description)) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700785 bundle_group_ = *new_bundle_group;
786 }
Zhi Huange830e682018-03-30 10:48:35 -0700787
788 if (!bundled_mid()) {
789 return RTCError::OK();
790 }
791
792 auto bundled_content = description->GetContentByName(*bundled_mid());
793 if (!bundled_content) {
794 return RTCError(
795 RTCErrorType::INVALID_PARAMETER,
796 "An m= section associated with the BUNDLE-tag doesn't exist.");
797 }
798
799 // If the |bundled_content| is rejected, other contents in the bundle group
800 // should be rejected.
801 if (bundled_content->rejected) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100802 for (const auto& content_name : bundle_group_->content_names()) {
Zhi Huange830e682018-03-30 10:48:35 -0700803 auto other_content = description->GetContentByName(content_name);
804 if (!other_content->rejected) {
805 return RTCError(
806 RTCErrorType::INVALID_PARAMETER,
807 "The m= section:" + content_name + " should be rejected.");
808 }
809 }
810 }
811
812 return RTCError::OK();
813}
814
815RTCError JsepTransportController::ValidateContent(
816 const cricket::ContentInfo& content_info) {
817 if (config_.rtcp_mux_policy ==
818 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
819 content_info.type == cricket::MediaProtocolType::kRtp &&
820 !content_info.media_description()->rtcp_mux()) {
821 return RTCError(RTCErrorType::INVALID_PARAMETER,
822 "The m= section:" + content_info.name +
823 " is invalid. RTCP-MUX is not "
824 "enabled when it is required.");
825 }
826 return RTCError::OK();
827}
828
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700829void JsepTransportController::HandleRejectedContent(
Zhi Huangd2248f82018-04-10 14:41:03 -0700830 const cricket::ContentInfo& content_info,
831 const cricket::SessionDescription* description) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800832 // If the content is rejected, let the
833 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700834 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700835 RemoveTransportForMid(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700836 if (content_info.name == bundled_mid()) {
Mirko Bonadei739baf02019-01-27 17:29:42 +0100837 for (const auto& content_name : bundle_group_->content_names()) {
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700838 RemoveTransportForMid(content_name);
Zhi Huange830e682018-03-30 10:48:35 -0700839 }
840 bundle_group_.reset();
841 } else if (IsBundled(content_info.name)) {
842 // Remove the rejected content from the |bundle_group_|.
Zhi Huange818b6e2018-02-22 15:26:27 -0800843 bundle_group_->RemoveContentName(content_info.name);
Zhi Huange830e682018-03-30 10:48:35 -0700844 // Reset the bundle group if nothing left.
845 if (!bundle_group_->FirstContentName()) {
846 bundle_group_.reset();
847 }
Zhi Huange818b6e2018-02-22 15:26:27 -0800848 }
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700849 MaybeDestroyJsepTransport(content_info.name);
Zhi Huange818b6e2018-02-22 15:26:27 -0800850}
851
Zhi Huang365381f2018-04-13 16:44:34 -0700852bool JsepTransportController::HandleBundledContent(
Zhi Huange818b6e2018-02-22 15:26:27 -0800853 const cricket::ContentInfo& content_info) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700854 auto jsep_transport = GetJsepTransportByName(*bundled_mid());
855 RTC_DCHECK(jsep_transport);
Zhi Huange818b6e2018-02-22 15:26:27 -0800856 // If the content is bundled, let the
857 // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
Zhi Huang365381f2018-04-13 16:44:34 -0700858 // then destroy the cricket::JsepTransport.
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700859 if (SetTransportForMid(content_info.name, jsep_transport)) {
Piotr (Peter) Slatala10aeb2a2018-11-14 10:57:24 -0800860 // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
861 // because it means that we first create media transport and start
862 // connecting it, and then we destroy it. We will need to address it before
863 // video path is enabled.
Zhi Huang365381f2018-04-13 16:44:34 -0700864 MaybeDestroyJsepTransport(content_info.name);
865 return true;
866 }
867 return false;
Zhi Huange818b6e2018-02-22 15:26:27 -0800868}
869
Zhi Huang365381f2018-04-13 16:44:34 -0700870bool JsepTransportController::SetTransportForMid(
Zhi Huangd2248f82018-04-10 14:41:03 -0700871 const std::string& mid,
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700872 cricket::JsepTransport* jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700873 RTC_DCHECK(jsep_transport);
Zhi Huangd2248f82018-04-10 14:41:03 -0700874 if (mid_to_transport_[mid] == jsep_transport) {
Zhi Huang365381f2018-04-13 16:44:34 -0700875 return true;
Zhi Huangd2248f82018-04-10 14:41:03 -0700876 }
877
878 mid_to_transport_[mid] = jsep_transport;
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700879 return config_.transport_observer->OnTransportChanged(
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100880 mid, jsep_transport->rtp_transport(), jsep_transport->RtpDtlsTransport(),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700881 jsep_transport->media_transport(),
882 jsep_transport->data_channel_transport());
Zhi Huangd2248f82018-04-10 14:41:03 -0700883}
884
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700885void JsepTransportController::RemoveTransportForMid(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700886 bool ret = config_.transport_observer->OnTransportChanged(
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -0700887 mid, nullptr, nullptr, nullptr, nullptr);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -0700888 // Calling OnTransportChanged with nullptr should always succeed, since it is
889 // only expected to fail when adding media to a transport (not removing).
890 RTC_DCHECK(ret);
Zhi Huangd2248f82018-04-10 14:41:03 -0700891 mid_to_transport_.erase(mid);
892}
893
Zhi Huange818b6e2018-02-22 15:26:27 -0800894cricket::JsepTransportDescription
895JsepTransportController::CreateJsepTransportDescription(
Harald Alvestrand1716d392019-06-03 20:35:45 +0200896 const cricket::ContentInfo& content_info,
897 const cricket::TransportInfo& transport_info,
Zhi Huange830e682018-03-30 10:48:35 -0700898 const std::vector<int>& encrypted_extension_ids,
899 int rtp_abs_sendtime_extn_id) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800900 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200901 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800902 RTC_DCHECK(content_desc);
903 bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
904 ? true
905 : content_desc->rtcp_mux();
906
907 return cricket::JsepTransportDescription(
908 rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
Zhi Huange830e682018-03-30 10:48:35 -0700909 rtp_abs_sendtime_extn_id, transport_info.description);
Zhi Huange818b6e2018-02-22 15:26:27 -0800910}
911
912bool JsepTransportController::ShouldUpdateBundleGroup(
913 SdpType type,
914 const cricket::SessionDescription* description) {
915 if (config_.bundle_policy ==
916 PeerConnectionInterface::kBundlePolicyMaxBundle) {
917 return true;
918 }
919
920 if (type != SdpType::kAnswer) {
921 return false;
922 }
923
924 RTC_DCHECK(local_desc_ && remote_desc_);
925 const cricket::ContentGroup* local_bundle =
926 local_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
927 const cricket::ContentGroup* remote_bundle =
928 remote_desc_->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
929 return local_bundle && remote_bundle;
930}
931
932std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
933 const cricket::ContentInfo& content_info) {
934 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200935 content_info.media_description();
Zhi Huange818b6e2018-02-22 15:26:27 -0800936
Benjamin Wrighta54daf12018-10-11 15:33:17 -0700937 if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800938 return std::vector<int>();
939 }
940
941 std::vector<int> encrypted_header_extension_ids;
Mirko Bonadei739baf02019-01-27 17:29:42 +0100942 for (const auto& extension : content_desc->rtp_header_extensions()) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800943 if (!extension.encrypt) {
944 continue;
945 }
Steve Anton64b626b2019-01-28 17:25:26 -0800946 if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800947 encrypted_header_extension_ids.push_back(extension.id);
948 }
949 }
950 return encrypted_header_extension_ids;
951}
952
953std::vector<int>
954JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundle(
955 const cricket::SessionDescription* description) {
956 RTC_DCHECK(description);
957 RTC_DCHECK(bundle_group_);
958
959 std::vector<int> merged_ids;
960 // Union the encrypted header IDs in the group when bundle is enabled.
961 for (const cricket::ContentInfo& content_info : description->contents()) {
962 if (bundle_group_->HasContentName(content_info.name)) {
963 std::vector<int> extension_ids =
964 GetEncryptedHeaderExtensionIds(content_info);
965 for (int id : extension_ids) {
Steve Anton64b626b2019-01-28 17:25:26 -0800966 if (!absl::c_linear_search(merged_ids, id)) {
Zhi Huange818b6e2018-02-22 15:26:27 -0800967 merged_ids.push_back(id);
968 }
969 }
970 }
971 }
972 return merged_ids;
973}
974
Zhi Huange830e682018-03-30 10:48:35 -0700975int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
Zhi Huange818b6e2018-02-22 15:26:27 -0800976 const cricket::ContentInfo& content_info) {
Zhi Huange830e682018-03-30 10:48:35 -0700977 if (!config_.enable_external_auth) {
978 return -1;
Zhi Huange818b6e2018-02-22 15:26:27 -0800979 }
980
981 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +0200982 content_info.media_description();
Zhi Huange830e682018-03-30 10:48:35 -0700983
984 const webrtc::RtpExtension* send_time_extension =
985 webrtc::RtpExtension::FindHeaderExtensionByUri(
986 content_desc->rtp_header_extensions(),
987 webrtc::RtpExtension::kAbsSendTimeUri);
988 return send_time_extension ? send_time_extension->id : -1;
989}
990
Zhi Huang365381f2018-04-13 16:44:34 -0700991const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700992 const std::string& mid) const {
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 -0700997cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
Zhi Huange830e682018-03-30 10:48:35 -0700998 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -0700999 auto it = mid_to_transport_.find(mid);
1000 return it == mid_to_transport_.end() ? nullptr : it->second;
Zhi Huange830e682018-03-30 10:48:35 -07001001}
1002
Zhi Huang365381f2018-04-13 16:44:34 -07001003const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001004 const std::string& transport_name) const {
1005 auto it = jsep_transports_by_name_.find(transport_name);
1006 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1007}
1008
Zhi Huang365381f2018-04-13 16:44:34 -07001009cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
Zhi Huange830e682018-03-30 10:48:35 -07001010 const std::string& transport_name) {
1011 auto it = jsep_transports_by_name_.find(transport_name);
1012 return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
1013}
1014
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001015std::unique_ptr<webrtc::MediaTransportInterface>
1016JsepTransportController::MaybeCreateMediaTransport(
1017 const cricket::ContentInfo& content_info,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001018 const cricket::SessionDescription& description,
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001019 bool local) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001020 if (config_.media_transport_factory == nullptr) {
1021 return nullptr;
1022 }
1023
Piotr (Peter) Slatala55b91b92019-01-25 13:31:15 -08001024 if (!config_.use_media_transport_for_media &&
1025 !config_.use_media_transport_for_data_channels) {
1026 return nullptr;
1027 }
1028
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001029 // Caller (offerer) media transport.
1030 if (local) {
1031 if (offer_media_transport_) {
1032 RTC_LOG(LS_INFO) << "Offered media transport has now been activated.";
1033 return std::move(offer_media_transport_);
1034 } else {
1035 RTC_LOG(LS_INFO)
1036 << "Not returning media transport. Either SDES wasn't enabled, or "
1037 "media transport didn't return an offer earlier.";
1038 // Offer wasn't generated. Either because media transport didn't want it,
1039 // or because SDES wasn't enabled.
1040 return nullptr;
1041 }
Piotr (Peter) Slatala9f956252018-10-31 08:25:26 -07001042 }
1043
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001044 // Remote offer. If no x-mt lines, do not create media transport.
1045 if (description.MediaTransportSettings().empty()) {
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001046 return nullptr;
Anton Sukhanov7940da02018-10-10 10:34:49 -07001047 }
1048
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001049 // When bundle is enabled, two JsepTransports are created, and then
1050 // the second transport is destroyed (right away).
1051 // For media transport, we don't want to create the second
1052 // media transport in the first place.
1053 RTC_LOG(LS_INFO) << "Returning new, client media transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001054
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001055 RTC_DCHECK(!local)
1056 << "If media transport is used, you must call "
1057 "GenerateOrGetLastMediaTransportOffer before SetLocalDescription. You "
1058 "also "
1059 "must use kRtcpMuxPolicyRequire and kBundlePolicyMaxBundle with media "
1060 "transport.";
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001061 MediaTransportSettings settings;
1062 settings.is_caller = local;
Piotr (Peter) Slatala01fe3092019-02-15 12:05:50 -08001063 if (config_.use_media_transport_for_media) {
1064 settings.event_log = config_.event_log;
1065 }
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001066
1067 // Assume there is only one media transport (or if more, use the first one).
1068 if (!local && !description.MediaTransportSettings().empty() &&
1069 config_.media_transport_factory->GetTransportName() ==
1070 description.MediaTransportSettings()[0].transport_name) {
1071 settings.remote_transport_parameters =
1072 description.MediaTransportSettings()[0].transport_setting;
1073 }
1074
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001075 auto media_transport_result =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001076 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1077 settings);
Piotr (Peter) Slatala63a176b2019-01-25 08:25:33 -08001078
1079 // TODO(sukhanov): Proper error handling.
1080 RTC_CHECK(media_transport_result.ok());
1081
1082 return media_transport_result.MoveValue();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001083}
1084
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001085// TODO(sukhanov): Refactor to avoid code duplication for Media and Datagram
1086// transports setup.
1087std::unique_ptr<webrtc::DatagramTransportInterface>
1088JsepTransportController::MaybeCreateDatagramTransport(
1089 const cricket::ContentInfo& content_info,
1090 const cricket::SessionDescription& description,
1091 bool local) {
1092 if (config_.media_transport_factory == nullptr) {
1093 return nullptr;
1094 }
1095
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001096 if (!(config_.use_datagram_transport ||
1097 config_.use_datagram_transport_for_data_channels)) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001098 return nullptr;
1099 }
1100
1101 // Caller (offerer) datagram transport.
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001102 if (offer_datagram_transport_) {
1103 RTC_DCHECK(local);
1104 RTC_LOG(LS_INFO) << "Offered datagram transport has now been activated.";
1105 return std::move(offer_datagram_transport_);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001106 }
1107
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001108 const cricket::TransportDescription* transport_description =
1109 description.GetTransportDescriptionByName(content_info.mid());
1110 RTC_DCHECK(transport_description)
1111 << "Missing transport description for mid=" << content_info.mid();
1112
1113 if (!transport_description->opaque_parameters) {
1114 RTC_LOG(LS_INFO)
1115 << "No opaque transport parameters, not creating datagram transport";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001116 return nullptr;
1117 }
1118
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001119 if (transport_description->opaque_parameters->protocol !=
1120 config_.media_transport_factory->GetTransportName()) {
1121 RTC_LOG(LS_INFO) << "Opaque transport parameters for protocol="
1122 << transport_description->opaque_parameters->protocol
1123 << ", which does not match supported protocol="
1124 << config_.media_transport_factory->GetTransportName();
1125 return nullptr;
1126 }
1127
1128 RTC_DCHECK(!local);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001129 // When bundle is enabled, two JsepTransports are created, and then
1130 // the second transport is destroyed (right away).
1131 // For datagram transport, we don't want to create the second
1132 // datagram transport in the first place.
1133 RTC_LOG(LS_INFO) << "Returning new, client datagram transport.";
1134
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001135 MediaTransportSettings settings;
1136 settings.is_caller = local;
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001137 settings.remote_transport_parameters =
1138 transport_description->opaque_parameters->parameters;
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001139 settings.event_log = config_.event_log;
1140
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001141 auto datagram_transport_result =
1142 config_.media_transport_factory->CreateDatagramTransport(network_thread_,
1143 settings);
1144
1145 // TODO(sukhanov): Proper error handling.
1146 RTC_CHECK(datagram_transport_result.ok());
1147
1148 return datagram_transport_result.MoveValue();
1149}
1150
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001151RTCError JsepTransportController::MaybeCreateJsepTransport(
1152 bool local,
Piotr (Peter) Slatala105ded32019-02-27 14:26:15 -08001153 const cricket::ContentInfo& content_info,
1154 const cricket::SessionDescription& description) {
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001155 RTC_DCHECK(network_thread_->IsCurrent());
1156 cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1157 if (transport) {
1158 return RTCError::OK();
1159 }
1160
1161 const cricket::MediaContentDescription* content_desc =
Harald Alvestrand1716d392019-06-03 20:35:45 +02001162 content_info.media_description();
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001163 if (certificate_ && !content_desc->cryptos().empty()) {
1164 return RTCError(RTCErrorType::INVALID_PARAMETER,
1165 "SDES and DTLS-SRTP cannot be enabled at the same time.");
1166 }
1167
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001168 std::unique_ptr<cricket::IceTransportInternal> ice =
1169 CreateIceTransport(content_info.name, /*rtcp=*/false);
1170
1171 std::unique_ptr<MediaTransportInterface> media_transport =
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001172 MaybeCreateMediaTransport(content_info, description, local);
1173 if (media_transport) {
1174 media_transport_created_once_ = true;
1175 media_transport->Connect(ice.get());
1176 }
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001177
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001178 std::unique_ptr<DatagramTransportInterface> datagram_transport =
1179 MaybeCreateDatagramTransport(content_info, description, local);
1180 if (datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001181 datagram_transport->Connect(ice.get());
1182 }
1183
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001184 std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001185 CreateDtlsTransport(content_info, ice.get(), nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001186
1187 std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1188 std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1189 std::unique_ptr<SrtpTransport> sdes_transport;
1190 std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001191 std::unique_ptr<RtpTransportInternal> datagram_rtp_transport;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001192
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001193 std::unique_ptr<cricket::IceTransportInternal> rtcp_ice;
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001194 if (config_.rtcp_mux_policy !=
1195 PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1196 content_info.type == cricket::MediaProtocolType::kRtp) {
Piotr (Peter) Slatala2b5baee2019-01-16 08:25:21 -08001197 RTC_DCHECK(media_transport == nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001198 RTC_DCHECK(datagram_transport == nullptr);
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001199 rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
Anton Sukhanovac6c0962019-07-10 15:44:56 -07001200 rtcp_dtls_transport = CreateDtlsTransport(content_info, rtcp_ice.get(),
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001201 /*datagram_transport=*/nullptr);
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001202 }
Piotr (Peter) Slatala47dfdca2018-11-16 14:13:58 -08001203
Bjorn A Mellem703ea952019-08-23 10:31:11 -07001204 // Only create a datagram RTP transport if the datagram transport should be
1205 // used for RTP.
1206 if (datagram_transport && config_.use_datagram_transport) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001207 // TODO(sukhanov): We use unencrypted RTP transport over DatagramTransport,
1208 // because MediaTransport encrypts. In the future we may want to
1209 // implement our own version of RtpTransport over MediaTransport, because
1210 // it will give us more control over things like:
1211 // - Fusing
1212 // - Rtp header compression
1213 // - Handling Rtcp feedback.
1214 RTC_LOG(LS_INFO) << "Creating UnencryptedRtpTransport, because datagram "
1215 "transport is used.";
1216 RTC_DCHECK(!rtcp_dtls_transport);
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001217 datagram_rtp_transport = std::make_unique<DatagramRtpTransport>(
Bjorn A Mellem364b2672019-08-20 16:58:03 -07001218 content_info.media_description()->rtp_header_extensions(), ice.get(),
1219 datagram_transport.get());
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001220 }
1221
1222 if (config_.disable_encryption) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001223 RTC_LOG(LS_INFO)
1224 << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001225 unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
Zhi Huangd2248f82018-04-10 14:41:03 -07001226 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001227 } else if (!content_desc->cryptos().empty()) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001228 sdes_transport = CreateSdesTransport(
1229 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001230 RTC_LOG(LS_INFO) << "Creating SdesTransport.";
Zhi Huange818b6e2018-02-22 15:26:27 -08001231 } else {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001232 RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
Zhi Huangd2248f82018-04-10 14:41:03 -07001233 dtls_srtp_transport = CreateDtlsSrtpTransport(
1234 content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
Zhi Huange818b6e2018-02-22 15:26:27 -08001235 }
1236
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001237 std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
1238 if (config_.sctp_factory) {
1239 sctp_transport =
1240 config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
1241 }
1242
1243 DataChannelTransportInterface* data_channel_transport = nullptr;
1244 if (config_.use_datagram_transport_for_data_channels) {
1245 data_channel_transport = datagram_transport.get();
1246 } else if (config_.use_media_transport_for_data_channels) {
1247 data_channel_transport = media_transport.get();
1248 }
1249
Zhi Huang365381f2018-04-13 16:44:34 -07001250 std::unique_ptr<cricket::JsepTransport> jsep_transport =
Mirko Bonadei317a1f02019-09-17 17:06:18 +02001251 std::make_unique<cricket::JsepTransport>(
Bjorn A Mellem0c1c1b42019-05-29 17:34:13 -07001252 content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1253 std::move(unencrypted_rtp_transport), std::move(sdes_transport),
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001254 std::move(dtls_srtp_transport), std::move(datagram_rtp_transport),
1255 std::move(rtp_dtls_transport), std::move(rtcp_dtls_transport),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001256 std::move(sctp_transport), std::move(media_transport),
1257 std::move(datagram_transport), data_channel_transport);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001258
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001259 jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1260 this, &JsepTransportController::OnRtcpPacketReceived_n);
1261
Zhi Huange818b6e2018-02-22 15:26:27 -08001262 jsep_transport->SignalRtcpMuxActive.connect(
1263 this, &JsepTransportController::UpdateAggregateStates_n);
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001264 jsep_transport->SignalMediaTransportStateChanged.connect(
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001265 this, &JsepTransportController::OnMediaTransportStateChanged_n);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001266 jsep_transport->SignalDataChannelTransportNegotiated.connect(
1267 this, &JsepTransportController::OnDataChannelTransportNegotiated_n);
Taylor Brandstettercbaa2542018-04-16 16:42:14 -07001268 SetTransportForMid(content_info.name, jsep_transport.get());
Zhi Huange830e682018-03-30 10:48:35 -07001269
Zhi Huangd2248f82018-04-10 14:41:03 -07001270 jsep_transports_by_name_[content_info.name] = std::move(jsep_transport);
1271 UpdateAggregateStates_n();
Zhi Huange830e682018-03-30 10:48:35 -07001272 return RTCError::OK();
Zhi Huange818b6e2018-02-22 15:26:27 -08001273}
1274
1275void JsepTransportController::MaybeDestroyJsepTransport(
1276 const std::string& mid) {
Zhi Huangd2248f82018-04-10 14:41:03 -07001277 auto jsep_transport = GetJsepTransportByName(mid);
1278 if (!jsep_transport) {
1279 return;
1280 }
1281
1282 // Don't destroy the JsepTransport if there are still media sections referring
1283 // to it.
1284 for (const auto& kv : mid_to_transport_) {
1285 if (kv.second == jsep_transport) {
1286 return;
1287 }
1288 }
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001289
Zhi Huange830e682018-03-30 10:48:35 -07001290 jsep_transports_by_name_.erase(mid);
Zhi Huange818b6e2018-02-22 15:26:27 -08001291 UpdateAggregateStates_n();
1292}
1293
1294void JsepTransportController::DestroyAllJsepTransports_n() {
1295 RTC_DCHECK(network_thread_->IsCurrent());
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001296
1297 for (const auto& jsep_transport : jsep_transports_by_name_) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001298 config_.transport_observer->OnTransportChanged(
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001299 jsep_transport.first, nullptr, nullptr, nullptr, nullptr);
Piotr (Peter) Slatalacc8e8bb2018-11-15 08:26:19 -08001300 }
1301
Zhi Huange830e682018-03-30 10:48:35 -07001302 jsep_transports_by_name_.clear();
Zhi Huange818b6e2018-02-22 15:26:27 -08001303}
1304
1305void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1306 RTC_DCHECK(network_thread_->IsCurrent());
1307
1308 ice_role_ = ice_role;
1309 for (auto& dtls : GetDtlsTransports()) {
1310 dtls->ice_transport()->SetIceRole(ice_role_);
1311 }
1312}
1313
1314cricket::IceRole JsepTransportController::DetermineIceRole(
Zhi Huang365381f2018-04-13 16:44:34 -07001315 cricket::JsepTransport* jsep_transport,
Zhi Huange818b6e2018-02-22 15:26:27 -08001316 const cricket::TransportInfo& transport_info,
1317 SdpType type,
1318 bool local) {
1319 cricket::IceRole ice_role = ice_role_;
1320 auto tdesc = transport_info.description;
1321 if (local) {
1322 // The initial offer side may use ICE Lite, in which case, per RFC5245
1323 // Section 5.1.1, the answer side should take the controlling role if it is
1324 // in the full ICE mode.
1325 //
1326 // When both sides use ICE Lite, the initial offer side must take the
1327 // controlling role, and this is the default logic implemented in
1328 // SetLocalDescription in JsepTransportController.
1329 if (jsep_transport->remote_description() &&
1330 jsep_transport->remote_description()->transport_desc.ice_mode ==
1331 cricket::ICEMODE_LITE &&
1332 ice_role_ == cricket::ICEROLE_CONTROLLED &&
1333 tdesc.ice_mode == cricket::ICEMODE_FULL) {
1334 ice_role = cricket::ICEROLE_CONTROLLING;
1335 }
1336
1337 // Older versions of Chrome expect the ICE role to be re-determined when an
1338 // ICE restart occurs, and also don't perform conflict resolution correctly,
1339 // so for now we can't safely stop doing this, unless the application opts
1340 // in by setting |config_.redetermine_role_on_ice_restart_| to false. See:
1341 // https://bugs.chromium.org/p/chromium/issues/detail?id=628676
1342 // TODO(deadbeef): Remove this when these old versions of Chrome reach a low
1343 // enough population.
1344 if (config_.redetermine_role_on_ice_restart &&
1345 jsep_transport->local_description() &&
1346 cricket::IceCredentialsChanged(
1347 jsep_transport->local_description()->transport_desc.ice_ufrag,
1348 jsep_transport->local_description()->transport_desc.ice_pwd,
1349 tdesc.ice_ufrag, tdesc.ice_pwd) &&
1350 // Don't change the ICE role if the remote endpoint is ICE lite; we
1351 // should always be controlling in that case.
1352 (!jsep_transport->remote_description() ||
1353 jsep_transport->remote_description()->transport_desc.ice_mode !=
1354 cricket::ICEMODE_LITE)) {
1355 ice_role = (type == SdpType::kOffer) ? cricket::ICEROLE_CONTROLLING
1356 : cricket::ICEROLE_CONTROLLED;
1357 }
1358 } else {
1359 // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1360 // supports only ice_lite, this local endpoint should take the CONTROLLING
1361 // role.
1362 // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1363 // be in a TransportDescription in the first place...
1364 if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1365 tdesc.ice_mode == cricket::ICEMODE_LITE) {
1366 ice_role = cricket::ICEROLE_CONTROLLING;
1367 }
1368
1369 // If we use ICE Lite and the remote endpoint uses the full implementation
1370 // of ICE, the local endpoint must take the controlled role, and the other
1371 // side must be the controlling role.
1372 if (jsep_transport->local_description() &&
1373 jsep_transport->local_description()->transport_desc.ice_mode ==
1374 cricket::ICEMODE_LITE &&
1375 ice_role_ == cricket::ICEROLE_CONTROLLING &&
Zhi Huange830e682018-03-30 10:48:35 -07001376 tdesc.ice_mode == cricket::ICEMODE_FULL) {
Zhi Huange818b6e2018-02-22 15:26:27 -08001377 ice_role = cricket::ICEROLE_CONTROLLED;
1378 }
1379 }
1380
1381 return ice_role;
1382}
1383
1384void JsepTransportController::OnTransportWritableState_n(
1385 rtc::PacketTransportInternal* transport) {
1386 RTC_DCHECK(network_thread_->IsCurrent());
1387 RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1388 << " writability changed to " << transport->writable()
1389 << ".";
1390 UpdateAggregateStates_n();
1391}
1392
1393void JsepTransportController::OnTransportReceivingState_n(
1394 rtc::PacketTransportInternal* transport) {
1395 RTC_DCHECK(network_thread_->IsCurrent());
1396 UpdateAggregateStates_n();
1397}
1398
1399void JsepTransportController::OnTransportGatheringState_n(
1400 cricket::IceTransportInternal* transport) {
1401 RTC_DCHECK(network_thread_->IsCurrent());
1402 UpdateAggregateStates_n();
1403}
1404
1405void JsepTransportController::OnTransportCandidateGathered_n(
1406 cricket::IceTransportInternal* transport,
1407 const cricket::Candidate& candidate) {
1408 RTC_DCHECK(network_thread_->IsCurrent());
1409
1410 // We should never signal peer-reflexive candidates.
1411 if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1412 RTC_NOTREACHED();
1413 return;
1414 }
Steve Antond25828a2018-08-31 13:06:05 -07001415 std::string transport_name = transport->transport_name();
1416 invoker_.AsyncInvoke<void>(
1417 RTC_FROM_HERE, signaling_thread_, [this, transport_name, candidate] {
1418 SignalIceCandidatesGathered(transport_name, {candidate});
1419 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001420}
1421
Eldar Relloda13ea22019-06-01 12:23:43 +03001422void JsepTransportController::OnTransportCandidateError_n(
1423 cricket::IceTransportInternal* transport,
1424 const cricket::IceCandidateErrorEvent& event) {
1425 RTC_DCHECK(network_thread_->IsCurrent());
1426
1427 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1428 [this, event] { SignalIceCandidateError(event); });
1429}
Zhi Huange818b6e2018-02-22 15:26:27 -08001430void JsepTransportController::OnTransportCandidatesRemoved_n(
1431 cricket::IceTransportInternal* transport,
1432 const cricket::Candidates& candidates) {
1433 invoker_.AsyncInvoke<void>(
1434 RTC_FROM_HERE, signaling_thread_,
Steve Antond25828a2018-08-31 13:06:05 -07001435 [this, candidates] { SignalIceCandidatesRemoved(candidates); });
Zhi Huange818b6e2018-02-22 15:26:27 -08001436}
Alex Drake00c7ecf2019-08-06 10:54:47 -07001437void JsepTransportController::OnTransportCandidatePairChanged_n(
1438 const cricket::CandidatePairChangeEvent& event) {
1439 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this, event] {
1440 SignalIceCandidatePairChanged(event);
1441 });
1442}
Zhi Huange818b6e2018-02-22 15:26:27 -08001443
1444void JsepTransportController::OnTransportRoleConflict_n(
1445 cricket::IceTransportInternal* transport) {
1446 RTC_DCHECK(network_thread_->IsCurrent());
1447 // Note: since the role conflict is handled entirely on the network thread,
1448 // we don't need to worry about role conflicts occurring on two ports at
1449 // once. The first one encountered should immediately reverse the role.
1450 cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1451 ? cricket::ICEROLE_CONTROLLED
1452 : cricket::ICEROLE_CONTROLLING;
1453 RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1454 << (reversed_role == cricket::ICEROLE_CONTROLLING
1455 ? "controlling"
1456 : "controlled")
1457 << " role.";
1458 SetIceRole_n(reversed_role);
1459}
1460
1461void JsepTransportController::OnTransportStateChanged_n(
1462 cricket::IceTransportInternal* transport) {
1463 RTC_DCHECK(network_thread_->IsCurrent());
1464 RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1465 << transport->component()
1466 << " state changed. Check if state is complete.";
1467 UpdateAggregateStates_n();
1468}
1469
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001470void JsepTransportController::OnMediaTransportStateChanged_n() {
Bjorn Mellem175aa2e2018-11-08 11:23:22 -08001471 UpdateAggregateStates_n();
1472}
1473
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001474void JsepTransportController::OnDataChannelTransportNegotiated_n(
1475 cricket::JsepTransport* transport,
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001476 DataChannelTransportInterface* data_channel_transport) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001477 for (auto it : mid_to_transport_) {
1478 if (it.second == transport) {
1479 config_.transport_observer->OnTransportChanged(
1480 it.first, transport->rtp_transport(), transport->RtpDtlsTransport(),
Bjorn A Mellembc3eebc2019-09-23 14:53:54 -07001481 transport->media_transport(), data_channel_transport);
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001482 }
1483 }
1484}
1485
Zhi Huange818b6e2018-02-22 15:26:27 -08001486void JsepTransportController::UpdateAggregateStates_n() {
1487 RTC_DCHECK(network_thread_->IsCurrent());
1488
1489 auto dtls_transports = GetDtlsTransports();
Alex Loiko9289eda2018-11-23 16:18:59 +00001490 cricket::IceConnectionState new_connection_state =
1491 cricket::kIceConnectionConnecting;
Jonas Olsson635474e2018-10-18 15:58:17 +02001492 PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1493 PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1494 PeerConnectionInterface::PeerConnectionState new_combined_state =
1495 PeerConnectionInterface::PeerConnectionState::kNew;
Zhi Huange818b6e2018-02-22 15:26:27 -08001496 cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
Alex Loiko9289eda2018-11-23 16:18:59 +00001497 bool any_failed = false;
1498
1499 // TODO(http://bugs.webrtc.org/9719) If(when) media_transport disables
1500 // dtls_transports entirely, the below line will have to be changed to account
1501 // for the fact that dtls transports might be absent.
1502 bool all_connected = !dtls_transports.empty();
1503 bool all_completed = !dtls_transports.empty();
Zhi Huange818b6e2018-02-22 15:26:27 -08001504 bool any_gathering = false;
1505 bool all_done_gathering = !dtls_transports.empty();
Jonas Olsson635474e2018-10-18 15:58:17 +02001506
1507 std::map<IceTransportState, int> ice_state_counts;
1508 std::map<cricket::DtlsTransportState, int> dtls_state_counts;
1509
Zhi Huange818b6e2018-02-22 15:26:27 -08001510 for (const auto& dtls : dtls_transports) {
Alex Loiko9289eda2018-11-23 16:18:59 +00001511 any_failed = any_failed || dtls->ice_transport()->GetState() ==
1512 cricket::IceTransportState::STATE_FAILED;
1513 all_connected = all_connected && dtls->writable();
1514 all_completed =
1515 all_completed && dtls->writable() &&
1516 dtls->ice_transport()->GetState() ==
1517 cricket::IceTransportState::STATE_COMPLETED &&
1518 dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1519 dtls->ice_transport()->gathering_state() ==
1520 cricket::kIceGatheringComplete;
Zhi Huange818b6e2018-02-22 15:26:27 -08001521 any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1522 cricket::kIceGatheringNew;
1523 all_done_gathering =
1524 all_done_gathering && dtls->ice_transport()->gathering_state() ==
1525 cricket::kIceGatheringComplete;
Jonas Olsson635474e2018-10-18 15:58:17 +02001526
1527 dtls_state_counts[dtls->dtls_state()]++;
1528 ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
Zhi Huange818b6e2018-02-22 15:26:27 -08001529 }
Piotr (Peter) Slatala4eb41122018-11-01 07:26:03 -07001530
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001531 // Don't indicate that the call failed or isn't connected due to media
1532 // transport state unless the media transport is used for media. If it's only
1533 // used for data channels, it will signal those separately.
1534 if (config_.use_media_transport_for_media || config_.use_datagram_transport) {
1535 for (auto it = jsep_transports_by_name_.begin();
1536 it != jsep_transports_by_name_.end(); ++it) {
1537 auto jsep_transport = it->second.get();
1538 if (!jsep_transport->media_transport()) {
1539 continue;
1540 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001541
Bjorn A Mellemfa8f4ee2019-08-16 15:47:45 -07001542 // There is no 'kIceConnectionDisconnected', so we only need to handle
1543 // connected and completed.
1544 // We treat kClosed as failed, because if it happens before shutting down
1545 // media transports it means that there was a failure.
1546 // MediaTransportInterface allows to flip back and forth between kWritable
1547 // and kPending, but there does not exist an implementation that does
1548 // that, and the contract of jsep transport controller doesn't quite
1549 // expect that. When this happens, we would go from connected to
1550 // connecting state, but this may change in future.
1551 any_failed |= jsep_transport->media_transport_state() ==
1552 webrtc::MediaTransportState::kClosed;
1553 all_completed &= jsep_transport->media_transport_state() ==
1554 webrtc::MediaTransportState::kWritable;
1555 all_connected &= jsep_transport->media_transport_state() ==
1556 webrtc::MediaTransportState::kWritable;
1557 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001558 }
1559
1560 if (any_failed) {
1561 new_connection_state = cricket::kIceConnectionFailed;
1562 } else if (all_completed) {
1563 new_connection_state = cricket::kIceConnectionCompleted;
1564 } else if (all_connected) {
1565 new_connection_state = cricket::kIceConnectionConnected;
1566 }
1567 if (ice_connection_state_ != new_connection_state) {
1568 ice_connection_state_ = new_connection_state;
1569 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1570 [this, new_connection_state] {
1571 SignalIceConnectionState(new_connection_state);
1572 });
1573 }
1574
Jonas Olsson635474e2018-10-18 15:58:17 +02001575 // Compute the current RTCIceConnectionState as described in
1576 // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1577 // The PeerConnection is responsible for handling the "closed" state.
1578 int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1579 int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1580 int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1581 int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1582 int total_ice_disconnected =
1583 ice_state_counts[IceTransportState::kDisconnected];
1584 int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1585 int total_ice_new = ice_state_counts[IceTransportState::kNew];
1586 int total_ice = dtls_transports.size();
1587
1588 if (total_ice_failed > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001589 // Any RTCIceTransports are in the "failed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001590 new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
Alex Loiko9289eda2018-11-23 16:18:59 +00001591 } else if (total_ice_disconnected > 0) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001592 // None of the previous states apply and any RTCIceTransports are in the
1593 // "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001594 new_ice_connection_state =
1595 PeerConnectionInterface::kIceConnectionDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001596 } else if (total_ice_new + total_ice_closed == total_ice) {
1597 // None of the previous states apply and all RTCIceTransports are in the
1598 // "new" or "closed" state, or there are no transports.
1599 new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1600 } else if (total_ice_new + total_ice_checking > 0) {
1601 // None of the previous states apply and any RTCIceTransports are in the
1602 // "new" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001603 new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001604 } else if (total_ice_completed + total_ice_closed == total_ice ||
1605 all_completed) {
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001606 // None of the previous states apply and all RTCIceTransports are in the
1607 // "completed" or "closed" state.
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001608 //
1609 // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1610 // to mimic the behavior of the old ICE connection state, and should be
1611 // removed once we get end-of-candidates signaling in place.
Jonas Olsson635474e2018-10-18 15:58:17 +02001612 new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1613 } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001614 total_ice) {
1615 // None of the previous states apply and all RTCIceTransports are in the
1616 // "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001617 new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001618 } else {
1619 RTC_NOTREACHED();
1620 }
1621
Alex Loiko9289eda2018-11-23 16:18:59 +00001622 if (standardized_ice_connection_state_ != new_ice_connection_state) {
Jonas Olssonacd8ae72019-02-25 15:26:24 +01001623 if (standardized_ice_connection_state_ ==
1624 PeerConnectionInterface::kIceConnectionChecking &&
1625 new_ice_connection_state ==
1626 PeerConnectionInterface::kIceConnectionCompleted) {
1627 // Ensure that we never skip over the "connected" state.
1628 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_, [this] {
1629 SignalStandardizedIceConnectionState(
1630 PeerConnectionInterface::kIceConnectionConnected);
1631 });
1632 }
Alex Loiko9289eda2018-11-23 16:18:59 +00001633 standardized_ice_connection_state_ = new_ice_connection_state;
Jonas Olsson635474e2018-10-18 15:58:17 +02001634 invoker_.AsyncInvoke<void>(
1635 RTC_FROM_HERE, signaling_thread_, [this, new_ice_connection_state] {
Alex Loiko9289eda2018-11-23 16:18:59 +00001636 SignalStandardizedIceConnectionState(new_ice_connection_state);
Jonas Olsson635474e2018-10-18 15:58:17 +02001637 });
1638 }
1639
1640 // Compute the current RTCPeerConnectionState as described in
1641 // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1642 // The PeerConnection is responsible for handling the "closed" state.
1643 // Note that "connecting" is only a valid state for DTLS transports while
1644 // "checking", "completed" and "disconnected" are only valid for ICE
1645 // transports.
1646 int total_connected = total_ice_connected +
1647 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTED];
1648 int total_dtls_connecting =
1649 dtls_state_counts[cricket::DTLS_TRANSPORT_CONNECTING];
1650 int total_failed =
1651 total_ice_failed + dtls_state_counts[cricket::DTLS_TRANSPORT_FAILED];
1652 int total_closed =
1653 total_ice_closed + dtls_state_counts[cricket::DTLS_TRANSPORT_CLOSED];
1654 int total_new =
1655 total_ice_new + dtls_state_counts[cricket::DTLS_TRANSPORT_NEW];
1656 int total_transports = total_ice * 2;
1657
1658 if (total_failed > 0) {
1659 // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1660 new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001661 } else if (total_ice_disconnected > 0) {
1662 // None of the previous states apply and any RTCIceTransports or
1663 // RTCDtlsTransports are in the "disconnected" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001664 new_combined_state =
1665 PeerConnectionInterface::PeerConnectionState::kDisconnected;
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001666 } else if (total_new + total_closed == total_transports) {
1667 // None of the previous states apply and all RTCIceTransports and
1668 // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1669 // transports.
1670 new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1671 } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1672 // None of the previous states apply and all RTCIceTransports or
1673 // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001674 new_combined_state =
1675 PeerConnectionInterface::PeerConnectionState::kConnecting;
1676 } else if (total_connected + total_ice_completed + total_closed ==
Jonas Olsson6a8727b2018-12-07 13:11:44 +01001677 total_transports) {
1678 // None of the previous states apply and all RTCIceTransports and
1679 // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
Jonas Olsson635474e2018-10-18 15:58:17 +02001680 new_combined_state =
1681 PeerConnectionInterface::PeerConnectionState::kConnected;
Jonas Olsson635474e2018-10-18 15:58:17 +02001682 } else {
1683 RTC_NOTREACHED();
1684 }
1685
1686 if (combined_connection_state_ != new_combined_state) {
1687 combined_connection_state_ = new_combined_state;
1688 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1689 [this, new_combined_state] {
1690 SignalConnectionState(new_combined_state);
1691 });
1692 }
1693
Zhi Huange818b6e2018-02-22 15:26:27 -08001694 if (all_done_gathering) {
1695 new_gathering_state = cricket::kIceGatheringComplete;
1696 } else if (any_gathering) {
1697 new_gathering_state = cricket::kIceGatheringGathering;
1698 }
1699 if (ice_gathering_state_ != new_gathering_state) {
1700 ice_gathering_state_ = new_gathering_state;
Steve Antond25828a2018-08-31 13:06:05 -07001701 invoker_.AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread_,
1702 [this, new_gathering_state] {
1703 SignalIceGatheringState(new_gathering_state);
1704 });
Zhi Huange818b6e2018-02-22 15:26:27 -08001705 }
1706}
1707
Sebastian Jansson1b83a9e2019-09-18 18:22:12 +02001708void JsepTransportController::OnRtcpPacketReceived_n(
1709 rtc::CopyOnWriteBuffer* packet,
1710 int64_t packet_time_us) {
1711 RTC_DCHECK(config_.rtcp_handler);
1712 config_.rtcp_handler(*packet, packet_time_us);
1713}
1714
Zhi Huange818b6e2018-02-22 15:26:27 -08001715void JsepTransportController::OnDtlsHandshakeError(
1716 rtc::SSLHandshakeError error) {
1717 SignalDtlsHandshakeError(error);
1718}
1719
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001720absl::optional<cricket::SessionDescription::MediaTransportSetting>
1721JsepTransportController::GenerateOrGetLastMediaTransportOffer() {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001722 if (media_transport_created_once_) {
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001723 RTC_LOG(LS_INFO) << "Not regenerating media transport for the new offer in "
1724 "existing session.";
1725 return media_transport_offer_settings_;
1726 }
1727
1728 RTC_LOG(LS_INFO) << "Generating media transport offer!";
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001729
1730 absl::optional<std::string> transport_parameters;
1731
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001732 // Check that media transport is supposed to be used.
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001733 // Note that ICE is not available when media transport is created. It will
1734 // only be available in 'Connect'. This may be a potential server config, if
1735 // we decide to use this peer connection as a caller, not as a callee.
1736 // TODO(sukhanov): Avoid code duplication with CreateMedia/MediaTransport.
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001737 if (config_.use_media_transport_for_media ||
1738 config_.use_media_transport_for_data_channels) {
1739 RTC_DCHECK(config_.media_transport_factory != nullptr);
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001740 RTC_DCHECK(!config_.use_datagram_transport);
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001741 webrtc::MediaTransportSettings settings;
1742 settings.is_caller = true;
1743 settings.pre_shared_key = rtc::CreateRandomString(32);
Bjorn A Mellemb073f1c2019-07-02 09:50:35 -07001744 if (config_.use_media_transport_for_media) {
1745 settings.event_log = config_.event_log;
1746 }
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001747 auto media_transport_or_error =
1748 config_.media_transport_factory->CreateMediaTransport(network_thread_,
1749 settings);
1750
1751 if (media_transport_or_error.ok()) {
1752 offer_media_transport_ = std::move(media_transport_or_error.value());
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001753 transport_parameters =
1754 offer_media_transport_->GetTransportParametersOffer();
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001755 } else {
1756 RTC_LOG(LS_INFO) << "Unable to create media transport, error="
1757 << media_transport_or_error.error().message();
1758 }
1759 }
1760
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001761 if (!offer_media_transport_) {
Anton Sukhanov316f3ac2019-05-23 15:50:38 -07001762 RTC_LOG(LS_INFO) << "Media and data transports do not exist";
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001763 return absl::nullopt;
1764 }
1765
Piotr (Peter) Slatalab1ae10b2019-03-01 11:14:05 -08001766 if (!transport_parameters) {
1767 RTC_LOG(LS_INFO) << "Media transport didn't generate the offer";
1768 // Media transport didn't generate the offer, and is not supposed to be
1769 // used. Destroy the temporary media transport.
1770 offer_media_transport_ = nullptr;
1771 return absl::nullopt;
1772 }
1773
1774 cricket::SessionDescription::MediaTransportSetting setting;
1775 setting.transport_name = config_.media_transport_factory->GetTransportName();
1776 setting.transport_setting = *transport_parameters;
1777 media_transport_offer_settings_ = setting;
1778 return setting;
1779}
1780
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001781absl::optional<cricket::OpaqueTransportParameters>
1782JsepTransportController::GetTransportParameters(const std::string& mid) {
Bjorn A Mellemb689af42019-08-21 10:44:59 -07001783 if (!(config_.use_datagram_transport ||
1784 config_.use_datagram_transport_for_data_channels)) {
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001785 return absl::nullopt;
1786 }
1787
1788 cricket::JsepTransport* transport = GetJsepTransportForMid(mid);
1789 if (transport) {
1790 absl::optional<cricket::OpaqueTransportParameters> params =
1791 transport->GetTransportParameters();
1792 if (params) {
1793 params->protocol = config_.media_transport_factory->GetTransportName();
1794 }
1795 return params;
1796 }
1797
1798 RTC_DCHECK(!local_desc_ && !remote_desc_)
1799 << "JsepTransport should exist for every mid once any description is set";
1800
Bjorn A Mellem7da4e562019-09-26 11:02:11 -07001801 if (config_.use_datagram_transport_for_data_channels_receive_only) {
1802 return absl::nullopt;
1803 }
1804
Bjorn A Mellemc85ebbe2019-06-07 10:28:06 -07001805 // Need to generate a transport for the offer.
1806 if (!offer_datagram_transport_) {
1807 webrtc::MediaTransportSettings settings;
1808 settings.is_caller = true;
1809 settings.pre_shared_key = rtc::CreateRandomString(32);
1810 settings.event_log = config_.event_log;
1811 auto datagram_transport_or_error =
1812 config_.media_transport_factory->CreateDatagramTransport(
1813 network_thread_, settings);
1814
1815 if (datagram_transport_or_error.ok()) {
1816 offer_datagram_transport_ =
1817 std::move(datagram_transport_or_error.value());
1818 } else {
1819 RTC_LOG(LS_INFO) << "Unable to create datagram transport, error="
1820 << datagram_transport_or_error.error().message();
1821 }
1822 }
1823
1824 // We have prepared a transport for the offer, and can now use its parameters.
1825 cricket::OpaqueTransportParameters params;
1826 params.parameters = offer_datagram_transport_->GetTransportParameters();
1827 params.protocol = config_.media_transport_factory->GetTransportName();
1828 return params;
1829}
1830
Zhi Huange818b6e2018-02-22 15:26:27 -08001831} // namespace webrtc