xref: /aosp_15_r20/external/webrtc/pc/jsep_transport_controller.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2017 The WebRTC Project Authors. All rights reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "pc/jsep_transport_controller.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <stddef.h>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include <functional>
16*d9f75844SAndroid Build Coastguard Worker #include <memory>
17*d9f75844SAndroid Build Coastguard Worker #include <string>
18*d9f75844SAndroid Build Coastguard Worker #include <type_traits>
19*d9f75844SAndroid Build Coastguard Worker #include <utility>
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/dtls_transport_interface.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/rtp_parameters.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
25*d9f75844SAndroid Build Coastguard Worker #include "api/transport/enums.h"
26*d9f75844SAndroid Build Coastguard Worker #include "media/sctp/sctp_transport_internal.h"
27*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/dtls_transport.h"
28*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/ice_transport_internal.h"
29*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/p2p_constants.h"
30*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/port.h"
31*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
32*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
33*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread.h"
34*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/trace_event.h"
35*d9f75844SAndroid Build Coastguard Worker 
36*d9f75844SAndroid Build Coastguard Worker using webrtc::SdpType;
37*d9f75844SAndroid Build Coastguard Worker 
38*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
39*d9f75844SAndroid Build Coastguard Worker 
JsepTransportController(rtc::Thread * network_thread,cricket::PortAllocator * port_allocator,AsyncDnsResolverFactoryInterface * async_dns_resolver_factory,Config config)40*d9f75844SAndroid Build Coastguard Worker JsepTransportController::JsepTransportController(
41*d9f75844SAndroid Build Coastguard Worker     rtc::Thread* network_thread,
42*d9f75844SAndroid Build Coastguard Worker     cricket::PortAllocator* port_allocator,
43*d9f75844SAndroid Build Coastguard Worker     AsyncDnsResolverFactoryInterface* async_dns_resolver_factory,
44*d9f75844SAndroid Build Coastguard Worker     Config config)
45*d9f75844SAndroid Build Coastguard Worker     : network_thread_(network_thread),
46*d9f75844SAndroid Build Coastguard Worker       port_allocator_(port_allocator),
47*d9f75844SAndroid Build Coastguard Worker       async_dns_resolver_factory_(async_dns_resolver_factory),
48*d9f75844SAndroid Build Coastguard Worker       transports_(
49*d9f75844SAndroid Build Coastguard Worker           [this](const std::string& mid, cricket::JsepTransport* transport) {
50*d9f75844SAndroid Build Coastguard Worker             return OnTransportChanged(mid, transport);
51*d9f75844SAndroid Build Coastguard Worker           },
__anondb67ed740202() 52*d9f75844SAndroid Build Coastguard Worker           [this]() {
53*d9f75844SAndroid Build Coastguard Worker             RTC_DCHECK_RUN_ON(network_thread_);
54*d9f75844SAndroid Build Coastguard Worker             UpdateAggregateStates_n();
55*d9f75844SAndroid Build Coastguard Worker           }),
56*d9f75844SAndroid Build Coastguard Worker       config_(config),
57*d9f75844SAndroid Build Coastguard Worker       active_reset_srtp_params_(config.active_reset_srtp_params),
58*d9f75844SAndroid Build Coastguard Worker       bundles_(config.bundle_policy) {
59*d9f75844SAndroid Build Coastguard Worker   // The `transport_observer` is assumed to be non-null.
60*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(config_.transport_observer);
61*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(config_.rtcp_handler);
62*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(config_.ice_transport_factory);
63*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(config_.on_dtls_handshake_error_);
64*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(config_.field_trials);
65*d9f75844SAndroid Build Coastguard Worker   if (port_allocator_) {
66*d9f75844SAndroid Build Coastguard Worker     port_allocator_->SetIceTiebreaker(ice_tiebreaker_);
67*d9f75844SAndroid Build Coastguard Worker   }
68*d9f75844SAndroid Build Coastguard Worker }
69*d9f75844SAndroid Build Coastguard Worker 
~JsepTransportController()70*d9f75844SAndroid Build Coastguard Worker JsepTransportController::~JsepTransportController() {
71*d9f75844SAndroid Build Coastguard Worker   // Channel destructors may try to send packets, so this needs to happen on
72*d9f75844SAndroid Build Coastguard Worker   // the network thread.
73*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
74*d9f75844SAndroid Build Coastguard Worker   DestroyAllJsepTransports_n();
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker 
SetLocalDescription(SdpType type,const cricket::SessionDescription * description)77*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::SetLocalDescription(
78*d9f75844SAndroid Build Coastguard Worker     SdpType type,
79*d9f75844SAndroid Build Coastguard Worker     const cricket::SessionDescription* description) {
80*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "JsepTransportController::SetLocalDescription");
81*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
82*d9f75844SAndroid Build Coastguard Worker     return network_thread_->BlockingCall(
83*d9f75844SAndroid Build Coastguard Worker         [=] { return SetLocalDescription(type, description); });
84*d9f75844SAndroid Build Coastguard Worker   }
85*d9f75844SAndroid Build Coastguard Worker 
86*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
87*d9f75844SAndroid Build Coastguard Worker   if (!initial_offerer_.has_value()) {
88*d9f75844SAndroid Build Coastguard Worker     initial_offerer_.emplace(type == SdpType::kOffer);
89*d9f75844SAndroid Build Coastguard Worker     if (*initial_offerer_) {
90*d9f75844SAndroid Build Coastguard Worker       SetIceRole_n(cricket::ICEROLE_CONTROLLING);
91*d9f75844SAndroid Build Coastguard Worker     } else {
92*d9f75844SAndroid Build Coastguard Worker       SetIceRole_n(cricket::ICEROLE_CONTROLLED);
93*d9f75844SAndroid Build Coastguard Worker     }
94*d9f75844SAndroid Build Coastguard Worker   }
95*d9f75844SAndroid Build Coastguard Worker   return ApplyDescription_n(/*local=*/true, type, description);
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker 
SetRemoteDescription(SdpType type,const cricket::SessionDescription * description)98*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::SetRemoteDescription(
99*d9f75844SAndroid Build Coastguard Worker     SdpType type,
100*d9f75844SAndroid Build Coastguard Worker     const cricket::SessionDescription* description) {
101*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "JsepTransportController::SetRemoteDescription");
102*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
103*d9f75844SAndroid Build Coastguard Worker     return network_thread_->BlockingCall(
104*d9f75844SAndroid Build Coastguard Worker         [=] { return SetRemoteDescription(type, description); });
105*d9f75844SAndroid Build Coastguard Worker   }
106*d9f75844SAndroid Build Coastguard Worker 
107*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
108*d9f75844SAndroid Build Coastguard Worker   return ApplyDescription_n(/*local=*/false, type, description);
109*d9f75844SAndroid Build Coastguard Worker }
110*d9f75844SAndroid Build Coastguard Worker 
GetRtpTransport(absl::string_view mid) const111*d9f75844SAndroid Build Coastguard Worker RtpTransportInternal* JsepTransportController::GetRtpTransport(
112*d9f75844SAndroid Build Coastguard Worker     absl::string_view mid) const {
113*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
114*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportForMid(mid);
115*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
116*d9f75844SAndroid Build Coastguard Worker     return nullptr;
117*d9f75844SAndroid Build Coastguard Worker   }
118*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->rtp_transport();
119*d9f75844SAndroid Build Coastguard Worker }
120*d9f75844SAndroid Build Coastguard Worker 
GetDataChannelTransport(const std::string & mid) const121*d9f75844SAndroid Build Coastguard Worker DataChannelTransportInterface* JsepTransportController::GetDataChannelTransport(
122*d9f75844SAndroid Build Coastguard Worker     const std::string& mid) const {
123*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
124*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportForMid(mid);
125*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
126*d9f75844SAndroid Build Coastguard Worker     return nullptr;
127*d9f75844SAndroid Build Coastguard Worker   }
128*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->data_channel_transport();
129*d9f75844SAndroid Build Coastguard Worker }
130*d9f75844SAndroid Build Coastguard Worker 
GetDtlsTransport(const std::string & mid)131*d9f75844SAndroid Build Coastguard Worker cricket::DtlsTransportInternal* JsepTransportController::GetDtlsTransport(
132*d9f75844SAndroid Build Coastguard Worker     const std::string& mid) {
133*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
134*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportForMid(mid);
135*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
136*d9f75844SAndroid Build Coastguard Worker     return nullptr;
137*d9f75844SAndroid Build Coastguard Worker   }
138*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->rtp_dtls_transport();
139*d9f75844SAndroid Build Coastguard Worker }
140*d9f75844SAndroid Build Coastguard Worker 
141*d9f75844SAndroid Build Coastguard Worker const cricket::DtlsTransportInternal*
GetRtcpDtlsTransport(const std::string & mid) const142*d9f75844SAndroid Build Coastguard Worker JsepTransportController::GetRtcpDtlsTransport(const std::string& mid) const {
143*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
144*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportForMid(mid);
145*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
146*d9f75844SAndroid Build Coastguard Worker     return nullptr;
147*d9f75844SAndroid Build Coastguard Worker   }
148*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->rtcp_dtls_transport();
149*d9f75844SAndroid Build Coastguard Worker }
150*d9f75844SAndroid Build Coastguard Worker 
151*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::DtlsTransport>
LookupDtlsTransportByMid(const std::string & mid)152*d9f75844SAndroid Build Coastguard Worker JsepTransportController::LookupDtlsTransportByMid(const std::string& mid) {
153*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
154*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportForMid(mid);
155*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
156*d9f75844SAndroid Build Coastguard Worker     return nullptr;
157*d9f75844SAndroid Build Coastguard Worker   }
158*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->RtpDtlsTransport();
159*d9f75844SAndroid Build Coastguard Worker }
160*d9f75844SAndroid Build Coastguard Worker 
GetSctpTransport(const std::string & mid) const161*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpTransport> JsepTransportController::GetSctpTransport(
162*d9f75844SAndroid Build Coastguard Worker     const std::string& mid) const {
163*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
164*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportForMid(mid);
165*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
166*d9f75844SAndroid Build Coastguard Worker     return nullptr;
167*d9f75844SAndroid Build Coastguard Worker   }
168*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->SctpTransport();
169*d9f75844SAndroid Build Coastguard Worker }
170*d9f75844SAndroid Build Coastguard Worker 
SetIceConfig(const cricket::IceConfig & config)171*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::SetIceConfig(const cricket::IceConfig& config) {
172*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
173*d9f75844SAndroid Build Coastguard Worker   ice_config_ = config;
174*d9f75844SAndroid Build Coastguard Worker   for (auto& dtls : GetDtlsTransports()) {
175*d9f75844SAndroid Build Coastguard Worker     dtls->ice_transport()->SetIceConfig(ice_config_);
176*d9f75844SAndroid Build Coastguard Worker   }
177*d9f75844SAndroid Build Coastguard Worker }
178*d9f75844SAndroid Build Coastguard Worker 
SetNeedsIceRestartFlag()179*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::SetNeedsIceRestartFlag() {
180*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
181*d9f75844SAndroid Build Coastguard Worker   for (auto& transport : transports_.Transports()) {
182*d9f75844SAndroid Build Coastguard Worker     transport->SetNeedsIceRestartFlag();
183*d9f75844SAndroid Build Coastguard Worker   }
184*d9f75844SAndroid Build Coastguard Worker }
185*d9f75844SAndroid Build Coastguard Worker 
NeedsIceRestart(const std::string & transport_name) const186*d9f75844SAndroid Build Coastguard Worker bool JsepTransportController::NeedsIceRestart(
187*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name) const {
188*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
189*d9f75844SAndroid Build Coastguard Worker 
190*d9f75844SAndroid Build Coastguard Worker   const cricket::JsepTransport* transport =
191*d9f75844SAndroid Build Coastguard Worker       GetJsepTransportByName(transport_name);
192*d9f75844SAndroid Build Coastguard Worker   if (!transport) {
193*d9f75844SAndroid Build Coastguard Worker     return false;
194*d9f75844SAndroid Build Coastguard Worker   }
195*d9f75844SAndroid Build Coastguard Worker   return transport->needs_ice_restart();
196*d9f75844SAndroid Build Coastguard Worker }
197*d9f75844SAndroid Build Coastguard Worker 
GetDtlsRole(const std::string & mid) const198*d9f75844SAndroid Build Coastguard Worker absl::optional<rtc::SSLRole> JsepTransportController::GetDtlsRole(
199*d9f75844SAndroid Build Coastguard Worker     const std::string& mid) const {
200*d9f75844SAndroid Build Coastguard Worker   // TODO(tommi): Remove this hop. Currently it's called from the signaling
201*d9f75844SAndroid Build Coastguard Worker   // thread during negotiations, potentially multiple times.
202*d9f75844SAndroid Build Coastguard Worker   // WebRtcSessionDescriptionFactory::InternalCreateAnswer is one example.
203*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
204*d9f75844SAndroid Build Coastguard Worker     return network_thread_->BlockingCall([&] { return GetDtlsRole(mid); });
205*d9f75844SAndroid Build Coastguard Worker   }
206*d9f75844SAndroid Build Coastguard Worker 
207*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
208*d9f75844SAndroid Build Coastguard Worker 
209*d9f75844SAndroid Build Coastguard Worker   const cricket::JsepTransport* t = GetJsepTransportForMid(mid);
210*d9f75844SAndroid Build Coastguard Worker   if (!t) {
211*d9f75844SAndroid Build Coastguard Worker     return absl::optional<rtc::SSLRole>();
212*d9f75844SAndroid Build Coastguard Worker   }
213*d9f75844SAndroid Build Coastguard Worker   return t->GetDtlsRole();
214*d9f75844SAndroid Build Coastguard Worker }
215*d9f75844SAndroid Build Coastguard Worker 
SetLocalCertificate(const rtc::scoped_refptr<rtc::RTCCertificate> & certificate)216*d9f75844SAndroid Build Coastguard Worker bool JsepTransportController::SetLocalCertificate(
217*d9f75844SAndroid Build Coastguard Worker     const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
218*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
219*d9f75844SAndroid Build Coastguard Worker     return network_thread_->BlockingCall(
220*d9f75844SAndroid Build Coastguard Worker         [&] { return SetLocalCertificate(certificate); });
221*d9f75844SAndroid Build Coastguard Worker   }
222*d9f75844SAndroid Build Coastguard Worker 
223*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
224*d9f75844SAndroid Build Coastguard Worker 
225*d9f75844SAndroid Build Coastguard Worker   // Can't change a certificate, or set a null certificate.
226*d9f75844SAndroid Build Coastguard Worker   if (certificate_ || !certificate) {
227*d9f75844SAndroid Build Coastguard Worker     return false;
228*d9f75844SAndroid Build Coastguard Worker   }
229*d9f75844SAndroid Build Coastguard Worker   certificate_ = certificate;
230*d9f75844SAndroid Build Coastguard Worker 
231*d9f75844SAndroid Build Coastguard Worker   // Set certificate for JsepTransport, which verifies it matches the
232*d9f75844SAndroid Build Coastguard Worker   // fingerprint in SDP, and DTLS transport.
233*d9f75844SAndroid Build Coastguard Worker   // Fallback from DTLS to SDES is not supported.
234*d9f75844SAndroid Build Coastguard Worker   for (auto& transport : transports_.Transports()) {
235*d9f75844SAndroid Build Coastguard Worker     transport->SetLocalCertificate(certificate_);
236*d9f75844SAndroid Build Coastguard Worker   }
237*d9f75844SAndroid Build Coastguard Worker   for (auto& dtls : GetDtlsTransports()) {
238*d9f75844SAndroid Build Coastguard Worker     bool set_cert_success = dtls->SetLocalCertificate(certificate_);
239*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(set_cert_success);
240*d9f75844SAndroid Build Coastguard Worker   }
241*d9f75844SAndroid Build Coastguard Worker   return true;
242*d9f75844SAndroid Build Coastguard Worker }
243*d9f75844SAndroid Build Coastguard Worker 
244*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<rtc::RTCCertificate>
GetLocalCertificate(const std::string & transport_name) const245*d9f75844SAndroid Build Coastguard Worker JsepTransportController::GetLocalCertificate(
246*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name) const {
247*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
248*d9f75844SAndroid Build Coastguard Worker 
249*d9f75844SAndroid Build Coastguard Worker   const cricket::JsepTransport* t = GetJsepTransportByName(transport_name);
250*d9f75844SAndroid Build Coastguard Worker   if (!t) {
251*d9f75844SAndroid Build Coastguard Worker     return nullptr;
252*d9f75844SAndroid Build Coastguard Worker   }
253*d9f75844SAndroid Build Coastguard Worker   return t->GetLocalCertificate();
254*d9f75844SAndroid Build Coastguard Worker }
255*d9f75844SAndroid Build Coastguard Worker 
256*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<rtc::SSLCertChain>
GetRemoteSSLCertChain(const std::string & transport_name) const257*d9f75844SAndroid Build Coastguard Worker JsepTransportController::GetRemoteSSLCertChain(
258*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name) const {
259*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
260*d9f75844SAndroid Build Coastguard Worker 
261*d9f75844SAndroid Build Coastguard Worker   // Get the certificate from the RTP transport's DTLS handshake. Should be
262*d9f75844SAndroid Build Coastguard Worker   // identical to the RTCP transport's, since they were given the same remote
263*d9f75844SAndroid Build Coastguard Worker   // fingerprint.
264*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportByName(transport_name);
265*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
266*d9f75844SAndroid Build Coastguard Worker     return nullptr;
267*d9f75844SAndroid Build Coastguard Worker   }
268*d9f75844SAndroid Build Coastguard Worker   auto dtls = jsep_transport->rtp_dtls_transport();
269*d9f75844SAndroid Build Coastguard Worker   if (!dtls) {
270*d9f75844SAndroid Build Coastguard Worker     return nullptr;
271*d9f75844SAndroid Build Coastguard Worker   }
272*d9f75844SAndroid Build Coastguard Worker 
273*d9f75844SAndroid Build Coastguard Worker   return dtls->GetRemoteSSLCertChain();
274*d9f75844SAndroid Build Coastguard Worker }
275*d9f75844SAndroid Build Coastguard Worker 
MaybeStartGathering()276*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::MaybeStartGathering() {
277*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
278*d9f75844SAndroid Build Coastguard Worker     network_thread_->BlockingCall([&] { MaybeStartGathering(); });
279*d9f75844SAndroid Build Coastguard Worker     return;
280*d9f75844SAndroid Build Coastguard Worker   }
281*d9f75844SAndroid Build Coastguard Worker 
282*d9f75844SAndroid Build Coastguard Worker   for (auto& dtls : GetDtlsTransports()) {
283*d9f75844SAndroid Build Coastguard Worker     dtls->ice_transport()->MaybeStartGathering();
284*d9f75844SAndroid Build Coastguard Worker   }
285*d9f75844SAndroid Build Coastguard Worker }
286*d9f75844SAndroid Build Coastguard Worker 
AddRemoteCandidates(const std::string & transport_name,const cricket::Candidates & candidates)287*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::AddRemoteCandidates(
288*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name,
289*d9f75844SAndroid Build Coastguard Worker     const cricket::Candidates& candidates) {
290*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
291*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(VerifyCandidates(candidates).ok());
292*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport = GetJsepTransportByName(transport_name);
293*d9f75844SAndroid Build Coastguard Worker   if (!jsep_transport) {
294*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_WARNING) << "Not adding candidate because the JsepTransport "
295*d9f75844SAndroid Build Coastguard Worker                            "doesn't exist. Ignore it.";
296*d9f75844SAndroid Build Coastguard Worker     return RTCError::OK();
297*d9f75844SAndroid Build Coastguard Worker   }
298*d9f75844SAndroid Build Coastguard Worker   return jsep_transport->AddRemoteCandidates(candidates);
299*d9f75844SAndroid Build Coastguard Worker }
300*d9f75844SAndroid Build Coastguard Worker 
RemoveRemoteCandidates(const cricket::Candidates & candidates)301*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::RemoveRemoteCandidates(
302*d9f75844SAndroid Build Coastguard Worker     const cricket::Candidates& candidates) {
303*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
304*d9f75844SAndroid Build Coastguard Worker     return network_thread_->BlockingCall(
305*d9f75844SAndroid Build Coastguard Worker         [&] { return RemoveRemoteCandidates(candidates); });
306*d9f75844SAndroid Build Coastguard Worker   }
307*d9f75844SAndroid Build Coastguard Worker 
308*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
309*d9f75844SAndroid Build Coastguard Worker 
310*d9f75844SAndroid Build Coastguard Worker   // Verify each candidate before passing down to the transport layer.
311*d9f75844SAndroid Build Coastguard Worker   RTCError error = VerifyCandidates(candidates);
312*d9f75844SAndroid Build Coastguard Worker   if (!error.ok()) {
313*d9f75844SAndroid Build Coastguard Worker     return error;
314*d9f75844SAndroid Build Coastguard Worker   }
315*d9f75844SAndroid Build Coastguard Worker 
316*d9f75844SAndroid Build Coastguard Worker   std::map<std::string, cricket::Candidates> candidates_by_transport_name;
317*d9f75844SAndroid Build Coastguard Worker   for (const cricket::Candidate& cand : candidates) {
318*d9f75844SAndroid Build Coastguard Worker     if (!cand.transport_name().empty()) {
319*d9f75844SAndroid Build Coastguard Worker       candidates_by_transport_name[cand.transport_name()].push_back(cand);
320*d9f75844SAndroid Build Coastguard Worker     } else {
321*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "Not removing candidate because it does not have a "
322*d9f75844SAndroid Build Coastguard Worker                            "transport name set: "
323*d9f75844SAndroid Build Coastguard Worker                         << cand.ToSensitiveString();
324*d9f75844SAndroid Build Coastguard Worker     }
325*d9f75844SAndroid Build Coastguard Worker   }
326*d9f75844SAndroid Build Coastguard Worker 
327*d9f75844SAndroid Build Coastguard Worker   for (const auto& kv : candidates_by_transport_name) {
328*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name = kv.first;
329*d9f75844SAndroid Build Coastguard Worker     const cricket::Candidates& candidates = kv.second;
330*d9f75844SAndroid Build Coastguard Worker     cricket::JsepTransport* jsep_transport =
331*d9f75844SAndroid Build Coastguard Worker         GetJsepTransportByName(transport_name);
332*d9f75844SAndroid Build Coastguard Worker     if (!jsep_transport) {
333*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING)
334*d9f75844SAndroid Build Coastguard Worker           << "Not removing candidate because the JsepTransport doesn't exist.";
335*d9f75844SAndroid Build Coastguard Worker       continue;
336*d9f75844SAndroid Build Coastguard Worker     }
337*d9f75844SAndroid Build Coastguard Worker     for (const cricket::Candidate& candidate : candidates) {
338*d9f75844SAndroid Build Coastguard Worker       cricket::DtlsTransportInternal* dtls =
339*d9f75844SAndroid Build Coastguard Worker           candidate.component() == cricket::ICE_CANDIDATE_COMPONENT_RTP
340*d9f75844SAndroid Build Coastguard Worker               ? jsep_transport->rtp_dtls_transport()
341*d9f75844SAndroid Build Coastguard Worker               : jsep_transport->rtcp_dtls_transport();
342*d9f75844SAndroid Build Coastguard Worker       if (dtls) {
343*d9f75844SAndroid Build Coastguard Worker         dtls->ice_transport()->RemoveRemoteCandidate(candidate);
344*d9f75844SAndroid Build Coastguard Worker       }
345*d9f75844SAndroid Build Coastguard Worker     }
346*d9f75844SAndroid Build Coastguard Worker   }
347*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
348*d9f75844SAndroid Build Coastguard Worker }
349*d9f75844SAndroid Build Coastguard Worker 
GetStats(const std::string & transport_name,cricket::TransportStats * stats)350*d9f75844SAndroid Build Coastguard Worker bool JsepTransportController::GetStats(const std::string& transport_name,
351*d9f75844SAndroid Build Coastguard Worker                                        cricket::TransportStats* stats) {
352*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
353*d9f75844SAndroid Build Coastguard Worker 
354*d9f75844SAndroid Build Coastguard Worker   cricket::JsepTransport* transport = GetJsepTransportByName(transport_name);
355*d9f75844SAndroid Build Coastguard Worker   if (!transport) {
356*d9f75844SAndroid Build Coastguard Worker     return false;
357*d9f75844SAndroid Build Coastguard Worker   }
358*d9f75844SAndroid Build Coastguard Worker   return transport->GetStats(stats);
359*d9f75844SAndroid Build Coastguard Worker }
360*d9f75844SAndroid Build Coastguard Worker 
SetActiveResetSrtpParams(bool active_reset_srtp_params)361*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::SetActiveResetSrtpParams(
362*d9f75844SAndroid Build Coastguard Worker     bool active_reset_srtp_params) {
363*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
364*d9f75844SAndroid Build Coastguard Worker     network_thread_->BlockingCall(
365*d9f75844SAndroid Build Coastguard Worker         [=] { SetActiveResetSrtpParams(active_reset_srtp_params); });
366*d9f75844SAndroid Build Coastguard Worker     return;
367*d9f75844SAndroid Build Coastguard Worker   }
368*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
369*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO)
370*d9f75844SAndroid Build Coastguard Worker       << "Updating the active_reset_srtp_params for JsepTransportController: "
371*d9f75844SAndroid Build Coastguard Worker       << active_reset_srtp_params;
372*d9f75844SAndroid Build Coastguard Worker   active_reset_srtp_params_ = active_reset_srtp_params;
373*d9f75844SAndroid Build Coastguard Worker   for (auto& transport : transports_.Transports()) {
374*d9f75844SAndroid Build Coastguard Worker     transport->SetActiveResetSrtpParams(active_reset_srtp_params);
375*d9f75844SAndroid Build Coastguard Worker   }
376*d9f75844SAndroid Build Coastguard Worker }
377*d9f75844SAndroid Build Coastguard Worker 
RollbackTransports()378*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::RollbackTransports() {
379*d9f75844SAndroid Build Coastguard Worker   if (!network_thread_->IsCurrent()) {
380*d9f75844SAndroid Build Coastguard Worker     return network_thread_->BlockingCall([=] { return RollbackTransports(); });
381*d9f75844SAndroid Build Coastguard Worker   }
382*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
383*d9f75844SAndroid Build Coastguard Worker   bundles_.Rollback();
384*d9f75844SAndroid Build Coastguard Worker   if (!transports_.RollbackTransports()) {
385*d9f75844SAndroid Build Coastguard Worker     LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
386*d9f75844SAndroid Build Coastguard Worker                          "Failed to roll back transport state.");
387*d9f75844SAndroid Build Coastguard Worker   }
388*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
389*d9f75844SAndroid Build Coastguard Worker }
390*d9f75844SAndroid Build Coastguard Worker 
391*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<webrtc::IceTransportInterface>
CreateIceTransport(const std::string & transport_name,bool rtcp)392*d9f75844SAndroid Build Coastguard Worker JsepTransportController::CreateIceTransport(const std::string& transport_name,
393*d9f75844SAndroid Build Coastguard Worker                                             bool rtcp) {
394*d9f75844SAndroid Build Coastguard Worker   int component = rtcp ? cricket::ICE_CANDIDATE_COMPONENT_RTCP
395*d9f75844SAndroid Build Coastguard Worker                        : cricket::ICE_CANDIDATE_COMPONENT_RTP;
396*d9f75844SAndroid Build Coastguard Worker 
397*d9f75844SAndroid Build Coastguard Worker   IceTransportInit init;
398*d9f75844SAndroid Build Coastguard Worker   init.set_port_allocator(port_allocator_);
399*d9f75844SAndroid Build Coastguard Worker   init.set_async_dns_resolver_factory(async_dns_resolver_factory_);
400*d9f75844SAndroid Build Coastguard Worker   init.set_event_log(config_.event_log);
401*d9f75844SAndroid Build Coastguard Worker   init.set_field_trials(config_.field_trials);
402*d9f75844SAndroid Build Coastguard Worker   auto transport = config_.ice_transport_factory->CreateIceTransport(
403*d9f75844SAndroid Build Coastguard Worker       transport_name, component, std::move(init));
404*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(transport);
405*d9f75844SAndroid Build Coastguard Worker   transport->internal()->SetIceRole(ice_role_);
406*d9f75844SAndroid Build Coastguard Worker   transport->internal()->SetIceTiebreaker(ice_tiebreaker_);
407*d9f75844SAndroid Build Coastguard Worker   transport->internal()->SetIceConfig(ice_config_);
408*d9f75844SAndroid Build Coastguard Worker   return transport;
409*d9f75844SAndroid Build Coastguard Worker }
410*d9f75844SAndroid Build Coastguard Worker 
411*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::DtlsTransportInternal>
CreateDtlsTransport(const cricket::ContentInfo & content_info,cricket::IceTransportInternal * ice)412*d9f75844SAndroid Build Coastguard Worker JsepTransportController::CreateDtlsTransport(
413*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info,
414*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* ice) {
415*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
416*d9f75844SAndroid Build Coastguard Worker 
417*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::DtlsTransportInternal> dtls;
418*d9f75844SAndroid Build Coastguard Worker 
419*d9f75844SAndroid Build Coastguard Worker   if (config_.dtls_transport_factory) {
420*d9f75844SAndroid Build Coastguard Worker     dtls = config_.dtls_transport_factory->CreateDtlsTransport(
421*d9f75844SAndroid Build Coastguard Worker         ice, config_.crypto_options, config_.ssl_max_version);
422*d9f75844SAndroid Build Coastguard Worker   } else {
423*d9f75844SAndroid Build Coastguard Worker     dtls = std::make_unique<cricket::DtlsTransport>(ice, config_.crypto_options,
424*d9f75844SAndroid Build Coastguard Worker                                                     config_.event_log,
425*d9f75844SAndroid Build Coastguard Worker                                                     config_.ssl_max_version);
426*d9f75844SAndroid Build Coastguard Worker   }
427*d9f75844SAndroid Build Coastguard Worker 
428*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(dtls);
429*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(ice, dtls->ice_transport());
430*d9f75844SAndroid Build Coastguard Worker 
431*d9f75844SAndroid Build Coastguard Worker   if (certificate_) {
432*d9f75844SAndroid Build Coastguard Worker     bool set_cert_success = dtls->SetLocalCertificate(certificate_);
433*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(set_cert_success);
434*d9f75844SAndroid Build Coastguard Worker   }
435*d9f75844SAndroid Build Coastguard Worker 
436*d9f75844SAndroid Build Coastguard Worker   // Connect to signals offered by the DTLS and ICE transport.
437*d9f75844SAndroid Build Coastguard Worker   dtls->SignalWritableState.connect(
438*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportWritableState_n);
439*d9f75844SAndroid Build Coastguard Worker   dtls->SignalReceivingState.connect(
440*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportReceivingState_n);
441*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalGatheringState.connect(
442*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportGatheringState_n);
443*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalCandidateGathered.connect(
444*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportCandidateGathered_n);
445*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalCandidateError.connect(
446*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportCandidateError_n);
447*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalCandidatesRemoved.connect(
448*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportCandidatesRemoved_n);
449*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalRoleConflict.connect(
450*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportRoleConflict_n);
451*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalStateChanged.connect(
452*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportStateChanged_n);
453*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalIceTransportStateChanged.connect(
454*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportStateChanged_n);
455*d9f75844SAndroid Build Coastguard Worker   dtls->ice_transport()->SignalCandidatePairChanged.connect(
456*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnTransportCandidatePairChanged_n);
457*d9f75844SAndroid Build Coastguard Worker 
458*d9f75844SAndroid Build Coastguard Worker   dtls->SubscribeDtlsHandshakeError(
459*d9f75844SAndroid Build Coastguard Worker       [this](rtc::SSLHandshakeError error) { OnDtlsHandshakeError(error); });
460*d9f75844SAndroid Build Coastguard Worker   return dtls;
461*d9f75844SAndroid Build Coastguard Worker }
462*d9f75844SAndroid Build Coastguard Worker 
463*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<webrtc::RtpTransport>
CreateUnencryptedRtpTransport(const std::string & transport_name,rtc::PacketTransportInternal * rtp_packet_transport,rtc::PacketTransportInternal * rtcp_packet_transport)464*d9f75844SAndroid Build Coastguard Worker JsepTransportController::CreateUnencryptedRtpTransport(
465*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name,
466*d9f75844SAndroid Build Coastguard Worker     rtc::PacketTransportInternal* rtp_packet_transport,
467*d9f75844SAndroid Build Coastguard Worker     rtc::PacketTransportInternal* rtcp_packet_transport) {
468*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
469*d9f75844SAndroid Build Coastguard Worker   auto unencrypted_rtp_transport =
470*d9f75844SAndroid Build Coastguard Worker       std::make_unique<RtpTransport>(rtcp_packet_transport == nullptr);
471*d9f75844SAndroid Build Coastguard Worker   unencrypted_rtp_transport->SetRtpPacketTransport(rtp_packet_transport);
472*d9f75844SAndroid Build Coastguard Worker   if (rtcp_packet_transport) {
473*d9f75844SAndroid Build Coastguard Worker     unencrypted_rtp_transport->SetRtcpPacketTransport(rtcp_packet_transport);
474*d9f75844SAndroid Build Coastguard Worker   }
475*d9f75844SAndroid Build Coastguard Worker   return unencrypted_rtp_transport;
476*d9f75844SAndroid Build Coastguard Worker }
477*d9f75844SAndroid Build Coastguard Worker 
478*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<webrtc::SrtpTransport>
CreateSdesTransport(const std::string & transport_name,cricket::DtlsTransportInternal * rtp_dtls_transport,cricket::DtlsTransportInternal * rtcp_dtls_transport)479*d9f75844SAndroid Build Coastguard Worker JsepTransportController::CreateSdesTransport(
480*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name,
481*d9f75844SAndroid Build Coastguard Worker     cricket::DtlsTransportInternal* rtp_dtls_transport,
482*d9f75844SAndroid Build Coastguard Worker     cricket::DtlsTransportInternal* rtcp_dtls_transport) {
483*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
484*d9f75844SAndroid Build Coastguard Worker   auto srtp_transport = std::make_unique<webrtc::SrtpTransport>(
485*d9f75844SAndroid Build Coastguard Worker       rtcp_dtls_transport == nullptr, *config_.field_trials);
486*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(rtp_dtls_transport);
487*d9f75844SAndroid Build Coastguard Worker   srtp_transport->SetRtpPacketTransport(rtp_dtls_transport);
488*d9f75844SAndroid Build Coastguard Worker   if (rtcp_dtls_transport) {
489*d9f75844SAndroid Build Coastguard Worker     srtp_transport->SetRtcpPacketTransport(rtcp_dtls_transport);
490*d9f75844SAndroid Build Coastguard Worker   }
491*d9f75844SAndroid Build Coastguard Worker   if (config_.enable_external_auth) {
492*d9f75844SAndroid Build Coastguard Worker     srtp_transport->EnableExternalAuth();
493*d9f75844SAndroid Build Coastguard Worker   }
494*d9f75844SAndroid Build Coastguard Worker   return srtp_transport;
495*d9f75844SAndroid Build Coastguard Worker }
496*d9f75844SAndroid Build Coastguard Worker 
497*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<webrtc::DtlsSrtpTransport>
CreateDtlsSrtpTransport(const std::string & transport_name,cricket::DtlsTransportInternal * rtp_dtls_transport,cricket::DtlsTransportInternal * rtcp_dtls_transport)498*d9f75844SAndroid Build Coastguard Worker JsepTransportController::CreateDtlsSrtpTransport(
499*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name,
500*d9f75844SAndroid Build Coastguard Worker     cricket::DtlsTransportInternal* rtp_dtls_transport,
501*d9f75844SAndroid Build Coastguard Worker     cricket::DtlsTransportInternal* rtcp_dtls_transport) {
502*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
503*d9f75844SAndroid Build Coastguard Worker   auto dtls_srtp_transport = std::make_unique<webrtc::DtlsSrtpTransport>(
504*d9f75844SAndroid Build Coastguard Worker       rtcp_dtls_transport == nullptr, *config_.field_trials);
505*d9f75844SAndroid Build Coastguard Worker   if (config_.enable_external_auth) {
506*d9f75844SAndroid Build Coastguard Worker     dtls_srtp_transport->EnableExternalAuth();
507*d9f75844SAndroid Build Coastguard Worker   }
508*d9f75844SAndroid Build Coastguard Worker 
509*d9f75844SAndroid Build Coastguard Worker   dtls_srtp_transport->SetDtlsTransports(rtp_dtls_transport,
510*d9f75844SAndroid Build Coastguard Worker                                          rtcp_dtls_transport);
511*d9f75844SAndroid Build Coastguard Worker   dtls_srtp_transport->SetActiveResetSrtpParams(active_reset_srtp_params_);
512*d9f75844SAndroid Build Coastguard Worker   // Capturing this in the callback because JsepTransportController will always
513*d9f75844SAndroid Build Coastguard Worker   // outlive the DtlsSrtpTransport.
514*d9f75844SAndroid Build Coastguard Worker   dtls_srtp_transport->SetOnDtlsStateChange([this]() {
515*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_RUN_ON(this->network_thread_);
516*d9f75844SAndroid Build Coastguard Worker     this->UpdateAggregateStates_n();
517*d9f75844SAndroid Build Coastguard Worker   });
518*d9f75844SAndroid Build Coastguard Worker   return dtls_srtp_transport;
519*d9f75844SAndroid Build Coastguard Worker }
520*d9f75844SAndroid Build Coastguard Worker 
521*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::DtlsTransportInternal*>
GetDtlsTransports()522*d9f75844SAndroid Build Coastguard Worker JsepTransportController::GetDtlsTransports() {
523*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
524*d9f75844SAndroid Build Coastguard Worker   std::vector<cricket::DtlsTransportInternal*> dtls_transports;
525*d9f75844SAndroid Build Coastguard Worker   for (auto jsep_transport : transports_.Transports()) {
526*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(jsep_transport);
527*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport->rtp_dtls_transport()) {
528*d9f75844SAndroid Build Coastguard Worker       dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
529*d9f75844SAndroid Build Coastguard Worker     }
530*d9f75844SAndroid Build Coastguard Worker 
531*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport->rtcp_dtls_transport()) {
532*d9f75844SAndroid Build Coastguard Worker       dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
533*d9f75844SAndroid Build Coastguard Worker     }
534*d9f75844SAndroid Build Coastguard Worker   }
535*d9f75844SAndroid Build Coastguard Worker   return dtls_transports;
536*d9f75844SAndroid Build Coastguard Worker }
537*d9f75844SAndroid Build Coastguard Worker 
538*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::DtlsTransportInternal*>
GetActiveDtlsTransports()539*d9f75844SAndroid Build Coastguard Worker JsepTransportController::GetActiveDtlsTransports() {
540*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(network_thread_);
541*d9f75844SAndroid Build Coastguard Worker   std::vector<cricket::DtlsTransportInternal*> dtls_transports;
542*d9f75844SAndroid Build Coastguard Worker   for (auto jsep_transport : transports_.ActiveTransports()) {
543*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(jsep_transport);
544*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport->rtp_dtls_transport()) {
545*d9f75844SAndroid Build Coastguard Worker       dtls_transports.push_back(jsep_transport->rtp_dtls_transport());
546*d9f75844SAndroid Build Coastguard Worker     }
547*d9f75844SAndroid Build Coastguard Worker 
548*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport->rtcp_dtls_transport()) {
549*d9f75844SAndroid Build Coastguard Worker       dtls_transports.push_back(jsep_transport->rtcp_dtls_transport());
550*d9f75844SAndroid Build Coastguard Worker     }
551*d9f75844SAndroid Build Coastguard Worker   }
552*d9f75844SAndroid Build Coastguard Worker   return dtls_transports;
553*d9f75844SAndroid Build Coastguard Worker }
554*d9f75844SAndroid Build Coastguard Worker 
ApplyDescription_n(bool local,SdpType type,const cricket::SessionDescription * description)555*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::ApplyDescription_n(
556*d9f75844SAndroid Build Coastguard Worker     bool local,
557*d9f75844SAndroid Build Coastguard Worker     SdpType type,
558*d9f75844SAndroid Build Coastguard Worker     const cricket::SessionDescription* description) {
559*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "JsepTransportController::ApplyDescription_n");
560*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(description);
561*d9f75844SAndroid Build Coastguard Worker 
562*d9f75844SAndroid Build Coastguard Worker   if (local) {
563*d9f75844SAndroid Build Coastguard Worker     local_desc_ = description;
564*d9f75844SAndroid Build Coastguard Worker   } else {
565*d9f75844SAndroid Build Coastguard Worker     remote_desc_ = description;
566*d9f75844SAndroid Build Coastguard Worker   }
567*d9f75844SAndroid Build Coastguard Worker 
568*d9f75844SAndroid Build Coastguard Worker   RTCError error;
569*d9f75844SAndroid Build Coastguard Worker   error = ValidateAndMaybeUpdateBundleGroups(local, type, description);
570*d9f75844SAndroid Build Coastguard Worker   if (!error.ok()) {
571*d9f75844SAndroid Build Coastguard Worker     return error;
572*d9f75844SAndroid Build Coastguard Worker   }
573*d9f75844SAndroid Build Coastguard Worker 
574*d9f75844SAndroid Build Coastguard Worker   std::map<const cricket::ContentGroup*, std::vector<int>>
575*d9f75844SAndroid Build Coastguard Worker       merged_encrypted_extension_ids_by_bundle;
576*d9f75844SAndroid Build Coastguard Worker   if (!bundles_.bundle_groups().empty()) {
577*d9f75844SAndroid Build Coastguard Worker     merged_encrypted_extension_ids_by_bundle =
578*d9f75844SAndroid Build Coastguard Worker         MergeEncryptedHeaderExtensionIdsForBundles(description);
579*d9f75844SAndroid Build Coastguard Worker   }
580*d9f75844SAndroid Build Coastguard Worker 
581*d9f75844SAndroid Build Coastguard Worker   for (const cricket::ContentInfo& content_info : description->contents()) {
582*d9f75844SAndroid Build Coastguard Worker     // Don't create transports for rejected m-lines and bundled m-lines.
583*d9f75844SAndroid Build Coastguard Worker     if (content_info.rejected ||
584*d9f75844SAndroid Build Coastguard Worker         !bundles_.IsFirstMidInGroup(content_info.name)) {
585*d9f75844SAndroid Build Coastguard Worker       continue;
586*d9f75844SAndroid Build Coastguard Worker     }
587*d9f75844SAndroid Build Coastguard Worker     error = MaybeCreateJsepTransport(local, content_info, *description);
588*d9f75844SAndroid Build Coastguard Worker     if (!error.ok()) {
589*d9f75844SAndroid Build Coastguard Worker       return error;
590*d9f75844SAndroid Build Coastguard Worker     }
591*d9f75844SAndroid Build Coastguard Worker   }
592*d9f75844SAndroid Build Coastguard Worker 
593*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(description->contents().size() ==
594*d9f75844SAndroid Build Coastguard Worker              description->transport_infos().size());
595*d9f75844SAndroid Build Coastguard Worker   for (size_t i = 0; i < description->contents().size(); ++i) {
596*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info = description->contents()[i];
597*d9f75844SAndroid Build Coastguard Worker     const cricket::TransportInfo& transport_info =
598*d9f75844SAndroid Build Coastguard Worker         description->transport_infos()[i];
599*d9f75844SAndroid Build Coastguard Worker 
600*d9f75844SAndroid Build Coastguard Worker     if (content_info.rejected) {
601*d9f75844SAndroid Build Coastguard Worker       // This may cause groups to be removed from |bundles_.bundle_groups()|.
602*d9f75844SAndroid Build Coastguard Worker       HandleRejectedContent(content_info);
603*d9f75844SAndroid Build Coastguard Worker       continue;
604*d9f75844SAndroid Build Coastguard Worker     }
605*d9f75844SAndroid Build Coastguard Worker 
606*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentGroup* established_bundle_group =
607*d9f75844SAndroid Build Coastguard Worker         bundles_.LookupGroupByMid(content_info.name);
608*d9f75844SAndroid Build Coastguard Worker 
609*d9f75844SAndroid Build Coastguard Worker     // For bundle members that are not BUNDLE-tagged (not first in the group),
610*d9f75844SAndroid Build Coastguard Worker     // configure their transport to be the same as the BUNDLE-tagged transport.
611*d9f75844SAndroid Build Coastguard Worker     if (established_bundle_group &&
612*d9f75844SAndroid Build Coastguard Worker         content_info.name != *established_bundle_group->FirstContentName()) {
613*d9f75844SAndroid Build Coastguard Worker       if (!HandleBundledContent(content_info, *established_bundle_group)) {
614*d9f75844SAndroid Build Coastguard Worker         return RTCError(RTCErrorType::INVALID_PARAMETER,
615*d9f75844SAndroid Build Coastguard Worker                         "Failed to process the bundled m= section with "
616*d9f75844SAndroid Build Coastguard Worker                         "mid='" +
617*d9f75844SAndroid Build Coastguard Worker                             content_info.name + "'.");
618*d9f75844SAndroid Build Coastguard Worker       }
619*d9f75844SAndroid Build Coastguard Worker       continue;
620*d9f75844SAndroid Build Coastguard Worker     }
621*d9f75844SAndroid Build Coastguard Worker 
622*d9f75844SAndroid Build Coastguard Worker     error = ValidateContent(content_info);
623*d9f75844SAndroid Build Coastguard Worker     if (!error.ok()) {
624*d9f75844SAndroid Build Coastguard Worker       return error;
625*d9f75844SAndroid Build Coastguard Worker     }
626*d9f75844SAndroid Build Coastguard Worker 
627*d9f75844SAndroid Build Coastguard Worker     std::vector<int> extension_ids;
628*d9f75844SAndroid Build Coastguard Worker     // Is BUNDLE-tagged (first in the group)?
629*d9f75844SAndroid Build Coastguard Worker     if (established_bundle_group &&
630*d9f75844SAndroid Build Coastguard Worker         content_info.name == *established_bundle_group->FirstContentName()) {
631*d9f75844SAndroid Build Coastguard Worker       auto it = merged_encrypted_extension_ids_by_bundle.find(
632*d9f75844SAndroid Build Coastguard Worker           established_bundle_group);
633*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK(it != merged_encrypted_extension_ids_by_bundle.end());
634*d9f75844SAndroid Build Coastguard Worker       extension_ids = it->second;
635*d9f75844SAndroid Build Coastguard Worker     } else {
636*d9f75844SAndroid Build Coastguard Worker       extension_ids = GetEncryptedHeaderExtensionIds(content_info);
637*d9f75844SAndroid Build Coastguard Worker     }
638*d9f75844SAndroid Build Coastguard Worker 
639*d9f75844SAndroid Build Coastguard Worker     int rtp_abs_sendtime_extn_id =
640*d9f75844SAndroid Build Coastguard Worker         GetRtpAbsSendTimeHeaderExtensionId(content_info);
641*d9f75844SAndroid Build Coastguard Worker 
642*d9f75844SAndroid Build Coastguard Worker     cricket::JsepTransport* transport =
643*d9f75844SAndroid Build Coastguard Worker         GetJsepTransportForMid(content_info.name);
644*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(transport);
645*d9f75844SAndroid Build Coastguard Worker 
646*d9f75844SAndroid Build Coastguard Worker     SetIceRole_n(DetermineIceRole(transport, transport_info, type, local));
647*d9f75844SAndroid Build Coastguard Worker 
648*d9f75844SAndroid Build Coastguard Worker     cricket::JsepTransportDescription jsep_description =
649*d9f75844SAndroid Build Coastguard Worker         CreateJsepTransportDescription(content_info, transport_info,
650*d9f75844SAndroid Build Coastguard Worker                                        extension_ids, rtp_abs_sendtime_extn_id);
651*d9f75844SAndroid Build Coastguard Worker     if (local) {
652*d9f75844SAndroid Build Coastguard Worker       error =
653*d9f75844SAndroid Build Coastguard Worker           transport->SetLocalJsepTransportDescription(jsep_description, type);
654*d9f75844SAndroid Build Coastguard Worker     } else {
655*d9f75844SAndroid Build Coastguard Worker       error =
656*d9f75844SAndroid Build Coastguard Worker           transport->SetRemoteJsepTransportDescription(jsep_description, type);
657*d9f75844SAndroid Build Coastguard Worker     }
658*d9f75844SAndroid Build Coastguard Worker 
659*d9f75844SAndroid Build Coastguard Worker     if (!error.ok()) {
660*d9f75844SAndroid Build Coastguard Worker       LOG_AND_RETURN_ERROR(
661*d9f75844SAndroid Build Coastguard Worker           RTCErrorType::INVALID_PARAMETER,
662*d9f75844SAndroid Build Coastguard Worker           "Failed to apply the description for m= section with mid='" +
663*d9f75844SAndroid Build Coastguard Worker               content_info.name + "': " + error.message());
664*d9f75844SAndroid Build Coastguard Worker     }
665*d9f75844SAndroid Build Coastguard Worker   }
666*d9f75844SAndroid Build Coastguard Worker   if (type == SdpType::kAnswer) {
667*d9f75844SAndroid Build Coastguard Worker     transports_.CommitTransports();
668*d9f75844SAndroid Build Coastguard Worker     bundles_.Commit();
669*d9f75844SAndroid Build Coastguard Worker   }
670*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
671*d9f75844SAndroid Build Coastguard Worker }
672*d9f75844SAndroid Build Coastguard Worker 
ValidateAndMaybeUpdateBundleGroups(bool local,SdpType type,const cricket::SessionDescription * description)673*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::ValidateAndMaybeUpdateBundleGroups(
674*d9f75844SAndroid Build Coastguard Worker     bool local,
675*d9f75844SAndroid Build Coastguard Worker     SdpType type,
676*d9f75844SAndroid Build Coastguard Worker     const cricket::SessionDescription* description) {
677*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(description);
678*d9f75844SAndroid Build Coastguard Worker 
679*d9f75844SAndroid Build Coastguard Worker   std::vector<const cricket::ContentGroup*> new_bundle_groups =
680*d9f75844SAndroid Build Coastguard Worker       description->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
681*d9f75844SAndroid Build Coastguard Worker   // Verify `new_bundle_groups`.
682*d9f75844SAndroid Build Coastguard Worker   std::map<std::string, const cricket::ContentGroup*> new_bundle_groups_by_mid;
683*d9f75844SAndroid Build Coastguard Worker   for (const cricket::ContentGroup* new_bundle_group : new_bundle_groups) {
684*d9f75844SAndroid Build Coastguard Worker     for (const std::string& content_name : new_bundle_group->content_names()) {
685*d9f75844SAndroid Build Coastguard Worker       // The BUNDLE group must not contain a MID that is a member of a different
686*d9f75844SAndroid Build Coastguard Worker       // BUNDLE group, or that contains the same MID multiple times.
687*d9f75844SAndroid Build Coastguard Worker       if (new_bundle_groups_by_mid.find(content_name) !=
688*d9f75844SAndroid Build Coastguard Worker           new_bundle_groups_by_mid.end()) {
689*d9f75844SAndroid Build Coastguard Worker         return RTCError(RTCErrorType::INVALID_PARAMETER,
690*d9f75844SAndroid Build Coastguard Worker                         "A BUNDLE group contains a MID='" + content_name +
691*d9f75844SAndroid Build Coastguard Worker                             "' that is already in a BUNDLE group.");
692*d9f75844SAndroid Build Coastguard Worker       }
693*d9f75844SAndroid Build Coastguard Worker       new_bundle_groups_by_mid.insert(
694*d9f75844SAndroid Build Coastguard Worker           std::make_pair(content_name, new_bundle_group));
695*d9f75844SAndroid Build Coastguard Worker       // The BUNDLE group must not contain a MID that no m= section has.
696*d9f75844SAndroid Build Coastguard Worker       if (!description->GetContentByName(content_name)) {
697*d9f75844SAndroid Build Coastguard Worker         return RTCError(RTCErrorType::INVALID_PARAMETER,
698*d9f75844SAndroid Build Coastguard Worker                         "A BUNDLE group contains a MID='" + content_name +
699*d9f75844SAndroid Build Coastguard Worker                             "' matching no m= section.");
700*d9f75844SAndroid Build Coastguard Worker       }
701*d9f75844SAndroid Build Coastguard Worker     }
702*d9f75844SAndroid Build Coastguard Worker   }
703*d9f75844SAndroid Build Coastguard Worker 
704*d9f75844SAndroid Build Coastguard Worker   if (type == SdpType::kOffer) {
705*d9f75844SAndroid Build Coastguard Worker     // For an offer, we need to verify that there is not a conflicting mapping
706*d9f75844SAndroid Build Coastguard Worker     // between existing and new bundle groups. For example, if the existing
707*d9f75844SAndroid Build Coastguard Worker     // groups are [[1,2],[3,4]] and new are [[1,3],[2,4]] or [[1,2,3,4]], or
708*d9f75844SAndroid Build Coastguard Worker     // vice versa. Switching things around like this requires a separate offer
709*d9f75844SAndroid Build Coastguard Worker     // that removes the relevant sections from their group, as per RFC 8843,
710*d9f75844SAndroid Build Coastguard Worker     // section 7.5.2.
711*d9f75844SAndroid Build Coastguard Worker     std::map<const cricket::ContentGroup*, const cricket::ContentGroup*>
712*d9f75844SAndroid Build Coastguard Worker         new_bundle_groups_by_existing_bundle_groups;
713*d9f75844SAndroid Build Coastguard Worker     std::map<const cricket::ContentGroup*, const cricket::ContentGroup*>
714*d9f75844SAndroid Build Coastguard Worker         existing_bundle_groups_by_new_bundle_groups;
715*d9f75844SAndroid Build Coastguard Worker     for (const cricket::ContentGroup* new_bundle_group : new_bundle_groups) {
716*d9f75844SAndroid Build Coastguard Worker       for (const std::string& mid : new_bundle_group->content_names()) {
717*d9f75844SAndroid Build Coastguard Worker         cricket::ContentGroup* existing_bundle_group =
718*d9f75844SAndroid Build Coastguard Worker             bundles_.LookupGroupByMid(mid);
719*d9f75844SAndroid Build Coastguard Worker         if (!existing_bundle_group) {
720*d9f75844SAndroid Build Coastguard Worker           continue;
721*d9f75844SAndroid Build Coastguard Worker         }
722*d9f75844SAndroid Build Coastguard Worker         auto it = new_bundle_groups_by_existing_bundle_groups.find(
723*d9f75844SAndroid Build Coastguard Worker             existing_bundle_group);
724*d9f75844SAndroid Build Coastguard Worker         if (it != new_bundle_groups_by_existing_bundle_groups.end() &&
725*d9f75844SAndroid Build Coastguard Worker             it->second != new_bundle_group) {
726*d9f75844SAndroid Build Coastguard Worker           return RTCError(RTCErrorType::INVALID_PARAMETER,
727*d9f75844SAndroid Build Coastguard Worker                           "MID " + mid + " in the offer has changed group.");
728*d9f75844SAndroid Build Coastguard Worker         }
729*d9f75844SAndroid Build Coastguard Worker         new_bundle_groups_by_existing_bundle_groups.insert(
730*d9f75844SAndroid Build Coastguard Worker             std::make_pair(existing_bundle_group, new_bundle_group));
731*d9f75844SAndroid Build Coastguard Worker         it = existing_bundle_groups_by_new_bundle_groups.find(new_bundle_group);
732*d9f75844SAndroid Build Coastguard Worker         if (it != existing_bundle_groups_by_new_bundle_groups.end() &&
733*d9f75844SAndroid Build Coastguard Worker             it->second != existing_bundle_group) {
734*d9f75844SAndroid Build Coastguard Worker           return RTCError(RTCErrorType::INVALID_PARAMETER,
735*d9f75844SAndroid Build Coastguard Worker                           "MID " + mid + " in the offer has changed group.");
736*d9f75844SAndroid Build Coastguard Worker         }
737*d9f75844SAndroid Build Coastguard Worker         existing_bundle_groups_by_new_bundle_groups.insert(
738*d9f75844SAndroid Build Coastguard Worker             std::make_pair(new_bundle_group, existing_bundle_group));
739*d9f75844SAndroid Build Coastguard Worker       }
740*d9f75844SAndroid Build Coastguard Worker     }
741*d9f75844SAndroid Build Coastguard Worker   } else if (type == SdpType::kAnswer) {
742*d9f75844SAndroid Build Coastguard Worker     std::vector<const cricket::ContentGroup*> offered_bundle_groups =
743*d9f75844SAndroid Build Coastguard Worker         local ? remote_desc_->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE)
744*d9f75844SAndroid Build Coastguard Worker               : local_desc_->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE);
745*d9f75844SAndroid Build Coastguard Worker 
746*d9f75844SAndroid Build Coastguard Worker     std::map<std::string, const cricket::ContentGroup*>
747*d9f75844SAndroid Build Coastguard Worker         offered_bundle_groups_by_mid;
748*d9f75844SAndroid Build Coastguard Worker     for (const cricket::ContentGroup* offered_bundle_group :
749*d9f75844SAndroid Build Coastguard Worker          offered_bundle_groups) {
750*d9f75844SAndroid Build Coastguard Worker       for (const std::string& content_name :
751*d9f75844SAndroid Build Coastguard Worker            offered_bundle_group->content_names()) {
752*d9f75844SAndroid Build Coastguard Worker         offered_bundle_groups_by_mid[content_name] = offered_bundle_group;
753*d9f75844SAndroid Build Coastguard Worker       }
754*d9f75844SAndroid Build Coastguard Worker     }
755*d9f75844SAndroid Build Coastguard Worker 
756*d9f75844SAndroid Build Coastguard Worker     std::map<const cricket::ContentGroup*, const cricket::ContentGroup*>
757*d9f75844SAndroid Build Coastguard Worker         new_bundle_groups_by_offered_bundle_groups;
758*d9f75844SAndroid Build Coastguard Worker     for (const cricket::ContentGroup* new_bundle_group : new_bundle_groups) {
759*d9f75844SAndroid Build Coastguard Worker       if (!new_bundle_group->FirstContentName()) {
760*d9f75844SAndroid Build Coastguard Worker         // Empty groups could be a subset of any group.
761*d9f75844SAndroid Build Coastguard Worker         continue;
762*d9f75844SAndroid Build Coastguard Worker       }
763*d9f75844SAndroid Build Coastguard Worker       // The group in the answer (new_bundle_group) must have a corresponding
764*d9f75844SAndroid Build Coastguard Worker       // group in the offer (original_group), because the answer groups may only
765*d9f75844SAndroid Build Coastguard Worker       // be subsets of the offer groups.
766*d9f75844SAndroid Build Coastguard Worker       auto it = offered_bundle_groups_by_mid.find(
767*d9f75844SAndroid Build Coastguard Worker           *new_bundle_group->FirstContentName());
768*d9f75844SAndroid Build Coastguard Worker       if (it == offered_bundle_groups_by_mid.end()) {
769*d9f75844SAndroid Build Coastguard Worker         return RTCError(RTCErrorType::INVALID_PARAMETER,
770*d9f75844SAndroid Build Coastguard Worker                         "A BUNDLE group was added in the answer that did not "
771*d9f75844SAndroid Build Coastguard Worker                         "exist in the offer.");
772*d9f75844SAndroid Build Coastguard Worker       }
773*d9f75844SAndroid Build Coastguard Worker       const cricket::ContentGroup* offered_bundle_group = it->second;
774*d9f75844SAndroid Build Coastguard Worker       if (new_bundle_groups_by_offered_bundle_groups.find(
775*d9f75844SAndroid Build Coastguard Worker               offered_bundle_group) !=
776*d9f75844SAndroid Build Coastguard Worker           new_bundle_groups_by_offered_bundle_groups.end()) {
777*d9f75844SAndroid Build Coastguard Worker         return RTCError(RTCErrorType::INVALID_PARAMETER,
778*d9f75844SAndroid Build Coastguard Worker                         "A MID in the answer has changed group.");
779*d9f75844SAndroid Build Coastguard Worker       }
780*d9f75844SAndroid Build Coastguard Worker       new_bundle_groups_by_offered_bundle_groups.insert(
781*d9f75844SAndroid Build Coastguard Worker           std::make_pair(offered_bundle_group, new_bundle_group));
782*d9f75844SAndroid Build Coastguard Worker       for (const std::string& content_name :
783*d9f75844SAndroid Build Coastguard Worker            new_bundle_group->content_names()) {
784*d9f75844SAndroid Build Coastguard Worker         it = offered_bundle_groups_by_mid.find(content_name);
785*d9f75844SAndroid Build Coastguard Worker         // The BUNDLE group in answer should be a subset of offered group.
786*d9f75844SAndroid Build Coastguard Worker         if (it == offered_bundle_groups_by_mid.end() ||
787*d9f75844SAndroid Build Coastguard Worker             it->second != offered_bundle_group) {
788*d9f75844SAndroid Build Coastguard Worker           return RTCError(RTCErrorType::INVALID_PARAMETER,
789*d9f75844SAndroid Build Coastguard Worker                           "A BUNDLE group in answer contains a MID='" +
790*d9f75844SAndroid Build Coastguard Worker                               content_name +
791*d9f75844SAndroid Build Coastguard Worker                               "' that was not in the offered group.");
792*d9f75844SAndroid Build Coastguard Worker         }
793*d9f75844SAndroid Build Coastguard Worker       }
794*d9f75844SAndroid Build Coastguard Worker     }
795*d9f75844SAndroid Build Coastguard Worker 
796*d9f75844SAndroid Build Coastguard Worker     for (const auto& bundle_group : bundles_.bundle_groups()) {
797*d9f75844SAndroid Build Coastguard Worker       for (const std::string& content_name : bundle_group->content_names()) {
798*d9f75844SAndroid Build Coastguard Worker         // An answer that removes m= sections from pre-negotiated BUNDLE group
799*d9f75844SAndroid Build Coastguard Worker         // without rejecting it, is invalid.
800*d9f75844SAndroid Build Coastguard Worker         auto it = new_bundle_groups_by_mid.find(content_name);
801*d9f75844SAndroid Build Coastguard Worker         if (it == new_bundle_groups_by_mid.end()) {
802*d9f75844SAndroid Build Coastguard Worker           auto* content_info = description->GetContentByName(content_name);
803*d9f75844SAndroid Build Coastguard Worker           if (!content_info || !content_info->rejected) {
804*d9f75844SAndroid Build Coastguard Worker             return RTCError(RTCErrorType::INVALID_PARAMETER,
805*d9f75844SAndroid Build Coastguard Worker                             "Answer cannot remove m= section with mid='" +
806*d9f75844SAndroid Build Coastguard Worker                                 content_name +
807*d9f75844SAndroid Build Coastguard Worker                                 "' from already-established BUNDLE group.");
808*d9f75844SAndroid Build Coastguard Worker           }
809*d9f75844SAndroid Build Coastguard Worker         }
810*d9f75844SAndroid Build Coastguard Worker       }
811*d9f75844SAndroid Build Coastguard Worker     }
812*d9f75844SAndroid Build Coastguard Worker   }
813*d9f75844SAndroid Build Coastguard Worker 
814*d9f75844SAndroid Build Coastguard Worker   if (config_.bundle_policy ==
815*d9f75844SAndroid Build Coastguard Worker           PeerConnectionInterface::kBundlePolicyMaxBundle &&
816*d9f75844SAndroid Build Coastguard Worker       !description->HasGroup(cricket::GROUP_TYPE_BUNDLE)) {
817*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
818*d9f75844SAndroid Build Coastguard Worker                     "max-bundle is used but no bundle group found.");
819*d9f75844SAndroid Build Coastguard Worker   }
820*d9f75844SAndroid Build Coastguard Worker 
821*d9f75844SAndroid Build Coastguard Worker   bundles_.Update(description, type);
822*d9f75844SAndroid Build Coastguard Worker 
823*d9f75844SAndroid Build Coastguard Worker   for (const auto& bundle_group : bundles_.bundle_groups()) {
824*d9f75844SAndroid Build Coastguard Worker     if (!bundle_group->FirstContentName())
825*d9f75844SAndroid Build Coastguard Worker       continue;
826*d9f75844SAndroid Build Coastguard Worker 
827*d9f75844SAndroid Build Coastguard Worker     // The first MID in a BUNDLE group is BUNDLE-tagged.
828*d9f75844SAndroid Build Coastguard Worker     auto bundled_content =
829*d9f75844SAndroid Build Coastguard Worker         description->GetContentByName(*bundle_group->FirstContentName());
830*d9f75844SAndroid Build Coastguard Worker     if (!bundled_content) {
831*d9f75844SAndroid Build Coastguard Worker       return RTCError(
832*d9f75844SAndroid Build Coastguard Worker           RTCErrorType::INVALID_PARAMETER,
833*d9f75844SAndroid Build Coastguard Worker           "An m= section associated with the BUNDLE-tag doesn't exist.");
834*d9f75844SAndroid Build Coastguard Worker     }
835*d9f75844SAndroid Build Coastguard Worker 
836*d9f75844SAndroid Build Coastguard Worker     // If the `bundled_content` is rejected, other contents in the bundle group
837*d9f75844SAndroid Build Coastguard Worker     // must also be rejected.
838*d9f75844SAndroid Build Coastguard Worker     if (bundled_content->rejected) {
839*d9f75844SAndroid Build Coastguard Worker       for (const auto& content_name : bundle_group->content_names()) {
840*d9f75844SAndroid Build Coastguard Worker         auto other_content = description->GetContentByName(content_name);
841*d9f75844SAndroid Build Coastguard Worker         if (!other_content->rejected) {
842*d9f75844SAndroid Build Coastguard Worker           return RTCError(RTCErrorType::INVALID_PARAMETER,
843*d9f75844SAndroid Build Coastguard Worker                           "The m= section with mid='" + content_name +
844*d9f75844SAndroid Build Coastguard Worker                               "' should be rejected.");
845*d9f75844SAndroid Build Coastguard Worker         }
846*d9f75844SAndroid Build Coastguard Worker       }
847*d9f75844SAndroid Build Coastguard Worker     }
848*d9f75844SAndroid Build Coastguard Worker   }
849*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
850*d9f75844SAndroid Build Coastguard Worker }
851*d9f75844SAndroid Build Coastguard Worker 
ValidateContent(const cricket::ContentInfo & content_info)852*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::ValidateContent(
853*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info) {
854*d9f75844SAndroid Build Coastguard Worker   if (config_.rtcp_mux_policy ==
855*d9f75844SAndroid Build Coastguard Worker           PeerConnectionInterface::kRtcpMuxPolicyRequire &&
856*d9f75844SAndroid Build Coastguard Worker       content_info.type == cricket::MediaProtocolType::kRtp &&
857*d9f75844SAndroid Build Coastguard Worker       !content_info.media_description()->rtcp_mux()) {
858*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
859*d9f75844SAndroid Build Coastguard Worker                     "The m= section with mid='" + content_info.name +
860*d9f75844SAndroid Build Coastguard Worker                         "' is invalid. RTCP-MUX is not "
861*d9f75844SAndroid Build Coastguard Worker                         "enabled when it is required.");
862*d9f75844SAndroid Build Coastguard Worker   }
863*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
864*d9f75844SAndroid Build Coastguard Worker }
865*d9f75844SAndroid Build Coastguard Worker 
HandleRejectedContent(const cricket::ContentInfo & content_info)866*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::HandleRejectedContent(
867*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info) {
868*d9f75844SAndroid Build Coastguard Worker   // If the content is rejected, let the
869*d9f75844SAndroid Build Coastguard Worker   // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
870*d9f75844SAndroid Build Coastguard Worker   // then destroy the cricket::JsepTransport.
871*d9f75844SAndroid Build Coastguard Worker   cricket::ContentGroup* bundle_group =
872*d9f75844SAndroid Build Coastguard Worker       bundles_.LookupGroupByMid(content_info.name);
873*d9f75844SAndroid Build Coastguard Worker   if (bundle_group && !bundle_group->content_names().empty() &&
874*d9f75844SAndroid Build Coastguard Worker       content_info.name == *bundle_group->FirstContentName()) {
875*d9f75844SAndroid Build Coastguard Worker     // Rejecting a BUNDLE group's first mid means we are rejecting the entire
876*d9f75844SAndroid Build Coastguard Worker     // group.
877*d9f75844SAndroid Build Coastguard Worker     for (const auto& content_name : bundle_group->content_names()) {
878*d9f75844SAndroid Build Coastguard Worker       transports_.RemoveTransportForMid(content_name);
879*d9f75844SAndroid Build Coastguard Worker     }
880*d9f75844SAndroid Build Coastguard Worker     // Delete the BUNDLE group.
881*d9f75844SAndroid Build Coastguard Worker     bundles_.DeleteGroup(bundle_group);
882*d9f75844SAndroid Build Coastguard Worker   } else {
883*d9f75844SAndroid Build Coastguard Worker     transports_.RemoveTransportForMid(content_info.name);
884*d9f75844SAndroid Build Coastguard Worker     if (bundle_group) {
885*d9f75844SAndroid Build Coastguard Worker       // Remove the rejected content from the `bundle_group`.
886*d9f75844SAndroid Build Coastguard Worker       bundles_.DeleteMid(bundle_group, content_info.name);
887*d9f75844SAndroid Build Coastguard Worker     }
888*d9f75844SAndroid Build Coastguard Worker   }
889*d9f75844SAndroid Build Coastguard Worker }
890*d9f75844SAndroid Build Coastguard Worker 
HandleBundledContent(const cricket::ContentInfo & content_info,const cricket::ContentGroup & bundle_group)891*d9f75844SAndroid Build Coastguard Worker bool JsepTransportController::HandleBundledContent(
892*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info,
893*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentGroup& bundle_group) {
894*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "JsepTransportController::HandleBundledContent");
895*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(bundle_group.FirstContentName());
896*d9f75844SAndroid Build Coastguard Worker   auto jsep_transport =
897*d9f75844SAndroid Build Coastguard Worker       GetJsepTransportByName(*bundle_group.FirstContentName());
898*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(jsep_transport);
899*d9f75844SAndroid Build Coastguard Worker   // If the content is bundled, let the
900*d9f75844SAndroid Build Coastguard Worker   // BaseChannel/SctpTransport change the RtpTransport/DtlsTransport first,
901*d9f75844SAndroid Build Coastguard Worker   // then destroy the cricket::JsepTransport.
902*d9f75844SAndroid Build Coastguard Worker   // TODO(bugs.webrtc.org/9719) For media transport this is far from ideal,
903*d9f75844SAndroid Build Coastguard Worker   // because it means that we first create media transport and start
904*d9f75844SAndroid Build Coastguard Worker   // connecting it, and then we destroy it. We will need to address it before
905*d9f75844SAndroid Build Coastguard Worker   // video path is enabled.
906*d9f75844SAndroid Build Coastguard Worker   return transports_.SetTransportForMid(content_info.name, jsep_transport);
907*d9f75844SAndroid Build Coastguard Worker }
908*d9f75844SAndroid Build Coastguard Worker 
909*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransportDescription
CreateJsepTransportDescription(const cricket::ContentInfo & content_info,const cricket::TransportInfo & transport_info,const std::vector<int> & encrypted_extension_ids,int rtp_abs_sendtime_extn_id)910*d9f75844SAndroid Build Coastguard Worker JsepTransportController::CreateJsepTransportDescription(
911*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info,
912*d9f75844SAndroid Build Coastguard Worker     const cricket::TransportInfo& transport_info,
913*d9f75844SAndroid Build Coastguard Worker     const std::vector<int>& encrypted_extension_ids,
914*d9f75844SAndroid Build Coastguard Worker     int rtp_abs_sendtime_extn_id) {
915*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc",
916*d9f75844SAndroid Build Coastguard Worker                "JsepTransportController::CreateJsepTransportDescription");
917*d9f75844SAndroid Build Coastguard Worker   const cricket::MediaContentDescription* content_desc =
918*d9f75844SAndroid Build Coastguard Worker       content_info.media_description();
919*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(content_desc);
920*d9f75844SAndroid Build Coastguard Worker   bool rtcp_mux_enabled = content_info.type == cricket::MediaProtocolType::kSctp
921*d9f75844SAndroid Build Coastguard Worker                               ? true
922*d9f75844SAndroid Build Coastguard Worker                               : content_desc->rtcp_mux();
923*d9f75844SAndroid Build Coastguard Worker 
924*d9f75844SAndroid Build Coastguard Worker   return cricket::JsepTransportDescription(
925*d9f75844SAndroid Build Coastguard Worker       rtcp_mux_enabled, content_desc->cryptos(), encrypted_extension_ids,
926*d9f75844SAndroid Build Coastguard Worker       rtp_abs_sendtime_extn_id, transport_info.description);
927*d9f75844SAndroid Build Coastguard Worker }
928*d9f75844SAndroid Build Coastguard Worker 
GetEncryptedHeaderExtensionIds(const cricket::ContentInfo & content_info)929*d9f75844SAndroid Build Coastguard Worker std::vector<int> JsepTransportController::GetEncryptedHeaderExtensionIds(
930*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info) {
931*d9f75844SAndroid Build Coastguard Worker   const cricket::MediaContentDescription* content_desc =
932*d9f75844SAndroid Build Coastguard Worker       content_info.media_description();
933*d9f75844SAndroid Build Coastguard Worker 
934*d9f75844SAndroid Build Coastguard Worker   if (!config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions) {
935*d9f75844SAndroid Build Coastguard Worker     return std::vector<int>();
936*d9f75844SAndroid Build Coastguard Worker   }
937*d9f75844SAndroid Build Coastguard Worker 
938*d9f75844SAndroid Build Coastguard Worker   std::vector<int> encrypted_header_extension_ids;
939*d9f75844SAndroid Build Coastguard Worker   for (const auto& extension : content_desc->rtp_header_extensions()) {
940*d9f75844SAndroid Build Coastguard Worker     if (!extension.encrypt) {
941*d9f75844SAndroid Build Coastguard Worker       continue;
942*d9f75844SAndroid Build Coastguard Worker     }
943*d9f75844SAndroid Build Coastguard Worker     if (!absl::c_linear_search(encrypted_header_extension_ids, extension.id)) {
944*d9f75844SAndroid Build Coastguard Worker       encrypted_header_extension_ids.push_back(extension.id);
945*d9f75844SAndroid Build Coastguard Worker     }
946*d9f75844SAndroid Build Coastguard Worker   }
947*d9f75844SAndroid Build Coastguard Worker   return encrypted_header_extension_ids;
948*d9f75844SAndroid Build Coastguard Worker }
949*d9f75844SAndroid Build Coastguard Worker 
950*d9f75844SAndroid Build Coastguard Worker std::map<const cricket::ContentGroup*, std::vector<int>>
MergeEncryptedHeaderExtensionIdsForBundles(const cricket::SessionDescription * description)951*d9f75844SAndroid Build Coastguard Worker JsepTransportController::MergeEncryptedHeaderExtensionIdsForBundles(
952*d9f75844SAndroid Build Coastguard Worker     const cricket::SessionDescription* description) {
953*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(description);
954*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!bundles_.bundle_groups().empty());
955*d9f75844SAndroid Build Coastguard Worker   std::map<const cricket::ContentGroup*, std::vector<int>>
956*d9f75844SAndroid Build Coastguard Worker       merged_encrypted_extension_ids_by_bundle;
957*d9f75844SAndroid Build Coastguard Worker   // Union the encrypted header IDs in the group when bundle is enabled.
958*d9f75844SAndroid Build Coastguard Worker   for (const cricket::ContentInfo& content_info : description->contents()) {
959*d9f75844SAndroid Build Coastguard Worker     auto group = bundles_.LookupGroupByMid(content_info.name);
960*d9f75844SAndroid Build Coastguard Worker     if (!group)
961*d9f75844SAndroid Build Coastguard Worker       continue;
962*d9f75844SAndroid Build Coastguard Worker     // Get or create list of IDs for the BUNDLE group.
963*d9f75844SAndroid Build Coastguard Worker     std::vector<int>& merged_ids =
964*d9f75844SAndroid Build Coastguard Worker         merged_encrypted_extension_ids_by_bundle[group];
965*d9f75844SAndroid Build Coastguard Worker     // Add IDs not already in the list.
966*d9f75844SAndroid Build Coastguard Worker     std::vector<int> extension_ids =
967*d9f75844SAndroid Build Coastguard Worker         GetEncryptedHeaderExtensionIds(content_info);
968*d9f75844SAndroid Build Coastguard Worker     for (int id : extension_ids) {
969*d9f75844SAndroid Build Coastguard Worker       if (!absl::c_linear_search(merged_ids, id)) {
970*d9f75844SAndroid Build Coastguard Worker         merged_ids.push_back(id);
971*d9f75844SAndroid Build Coastguard Worker       }
972*d9f75844SAndroid Build Coastguard Worker     }
973*d9f75844SAndroid Build Coastguard Worker   }
974*d9f75844SAndroid Build Coastguard Worker   return merged_encrypted_extension_ids_by_bundle;
975*d9f75844SAndroid Build Coastguard Worker }
976*d9f75844SAndroid Build Coastguard Worker 
GetRtpAbsSendTimeHeaderExtensionId(const cricket::ContentInfo & content_info)977*d9f75844SAndroid Build Coastguard Worker int JsepTransportController::GetRtpAbsSendTimeHeaderExtensionId(
978*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info) {
979*d9f75844SAndroid Build Coastguard Worker   if (!config_.enable_external_auth) {
980*d9f75844SAndroid Build Coastguard Worker     return -1;
981*d9f75844SAndroid Build Coastguard Worker   }
982*d9f75844SAndroid Build Coastguard Worker 
983*d9f75844SAndroid Build Coastguard Worker   const cricket::MediaContentDescription* content_desc =
984*d9f75844SAndroid Build Coastguard Worker       content_info.media_description();
985*d9f75844SAndroid Build Coastguard Worker 
986*d9f75844SAndroid Build Coastguard Worker   const webrtc::RtpExtension* send_time_extension =
987*d9f75844SAndroid Build Coastguard Worker       webrtc::RtpExtension::FindHeaderExtensionByUri(
988*d9f75844SAndroid Build Coastguard Worker           content_desc->rtp_header_extensions(),
989*d9f75844SAndroid Build Coastguard Worker           webrtc::RtpExtension::kAbsSendTimeUri,
990*d9f75844SAndroid Build Coastguard Worker           config_.crypto_options.srtp.enable_encrypted_rtp_header_extensions
991*d9f75844SAndroid Build Coastguard Worker               ? webrtc::RtpExtension::kPreferEncryptedExtension
992*d9f75844SAndroid Build Coastguard Worker               : webrtc::RtpExtension::kDiscardEncryptedExtension);
993*d9f75844SAndroid Build Coastguard Worker   return send_time_extension ? send_time_extension->id : -1;
994*d9f75844SAndroid Build Coastguard Worker }
995*d9f75844SAndroid Build Coastguard Worker 
GetJsepTransportForMid(const std::string & mid) const996*d9f75844SAndroid Build Coastguard Worker const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
997*d9f75844SAndroid Build Coastguard Worker     const std::string& mid) const {
998*d9f75844SAndroid Build Coastguard Worker   return transports_.GetTransportForMid(mid);
999*d9f75844SAndroid Build Coastguard Worker }
1000*d9f75844SAndroid Build Coastguard Worker 
GetJsepTransportForMid(const std::string & mid)1001*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
1002*d9f75844SAndroid Build Coastguard Worker     const std::string& mid) {
1003*d9f75844SAndroid Build Coastguard Worker   return transports_.GetTransportForMid(mid);
1004*d9f75844SAndroid Build Coastguard Worker }
GetJsepTransportForMid(absl::string_view mid) const1005*d9f75844SAndroid Build Coastguard Worker const cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
1006*d9f75844SAndroid Build Coastguard Worker     absl::string_view mid) const {
1007*d9f75844SAndroid Build Coastguard Worker   return transports_.GetTransportForMid(mid);
1008*d9f75844SAndroid Build Coastguard Worker }
1009*d9f75844SAndroid Build Coastguard Worker 
GetJsepTransportForMid(absl::string_view mid)1010*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* JsepTransportController::GetJsepTransportForMid(
1011*d9f75844SAndroid Build Coastguard Worker     absl::string_view mid) {
1012*d9f75844SAndroid Build Coastguard Worker   return transports_.GetTransportForMid(mid);
1013*d9f75844SAndroid Build Coastguard Worker }
1014*d9f75844SAndroid Build Coastguard Worker 
GetJsepTransportByName(const std::string & transport_name) const1015*d9f75844SAndroid Build Coastguard Worker const cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
1016*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name) const {
1017*d9f75844SAndroid Build Coastguard Worker   return transports_.GetTransportByName(transport_name);
1018*d9f75844SAndroid Build Coastguard Worker }
1019*d9f75844SAndroid Build Coastguard Worker 
GetJsepTransportByName(const std::string & transport_name)1020*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* JsepTransportController::GetJsepTransportByName(
1021*d9f75844SAndroid Build Coastguard Worker     const std::string& transport_name) {
1022*d9f75844SAndroid Build Coastguard Worker   return transports_.GetTransportByName(transport_name);
1023*d9f75844SAndroid Build Coastguard Worker }
1024*d9f75844SAndroid Build Coastguard Worker 
MaybeCreateJsepTransport(bool local,const cricket::ContentInfo & content_info,const cricket::SessionDescription & description)1025*d9f75844SAndroid Build Coastguard Worker RTCError JsepTransportController::MaybeCreateJsepTransport(
1026*d9f75844SAndroid Build Coastguard Worker     bool local,
1027*d9f75844SAndroid Build Coastguard Worker     const cricket::ContentInfo& content_info,
1028*d9f75844SAndroid Build Coastguard Worker     const cricket::SessionDescription& description) {
1029*d9f75844SAndroid Build Coastguard Worker   cricket::JsepTransport* transport = GetJsepTransportByName(content_info.name);
1030*d9f75844SAndroid Build Coastguard Worker   if (transport) {
1031*d9f75844SAndroid Build Coastguard Worker     return RTCError::OK();
1032*d9f75844SAndroid Build Coastguard Worker   }
1033*d9f75844SAndroid Build Coastguard Worker   const cricket::MediaContentDescription* content_desc =
1034*d9f75844SAndroid Build Coastguard Worker       content_info.media_description();
1035*d9f75844SAndroid Build Coastguard Worker   if (certificate_ && !content_desc->cryptos().empty()) {
1036*d9f75844SAndroid Build Coastguard Worker     return RTCError(RTCErrorType::INVALID_PARAMETER,
1037*d9f75844SAndroid Build Coastguard Worker                     "SDES and DTLS-SRTP cannot be enabled at the same time.");
1038*d9f75844SAndroid Build Coastguard Worker   }
1039*d9f75844SAndroid Build Coastguard Worker 
1040*d9f75844SAndroid Build Coastguard Worker   rtc::scoped_refptr<webrtc::IceTransportInterface> ice =
1041*d9f75844SAndroid Build Coastguard Worker       CreateIceTransport(content_info.name, /*rtcp=*/false);
1042*d9f75844SAndroid Build Coastguard Worker 
1043*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::DtlsTransportInternal> rtp_dtls_transport =
1044*d9f75844SAndroid Build Coastguard Worker       CreateDtlsTransport(content_info, ice->internal());
1045*d9f75844SAndroid Build Coastguard Worker 
1046*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::DtlsTransportInternal> rtcp_dtls_transport;
1047*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<RtpTransport> unencrypted_rtp_transport;
1048*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<SrtpTransport> sdes_transport;
1049*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<DtlsSrtpTransport> dtls_srtp_transport;
1050*d9f75844SAndroid Build Coastguard Worker 
1051*d9f75844SAndroid Build Coastguard Worker   rtc::scoped_refptr<webrtc::IceTransportInterface> rtcp_ice;
1052*d9f75844SAndroid Build Coastguard Worker   if (config_.rtcp_mux_policy !=
1053*d9f75844SAndroid Build Coastguard Worker           PeerConnectionInterface::kRtcpMuxPolicyRequire &&
1054*d9f75844SAndroid Build Coastguard Worker       content_info.type == cricket::MediaProtocolType::kRtp) {
1055*d9f75844SAndroid Build Coastguard Worker     rtcp_ice = CreateIceTransport(content_info.name, /*rtcp=*/true);
1056*d9f75844SAndroid Build Coastguard Worker     rtcp_dtls_transport =
1057*d9f75844SAndroid Build Coastguard Worker         CreateDtlsTransport(content_info, rtcp_ice->internal());
1058*d9f75844SAndroid Build Coastguard Worker   }
1059*d9f75844SAndroid Build Coastguard Worker 
1060*d9f75844SAndroid Build Coastguard Worker   if (config_.disable_encryption) {
1061*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO)
1062*d9f75844SAndroid Build Coastguard Worker         << "Creating UnencryptedRtpTransport, becayse encryption is disabled.";
1063*d9f75844SAndroid Build Coastguard Worker     unencrypted_rtp_transport = CreateUnencryptedRtpTransport(
1064*d9f75844SAndroid Build Coastguard Worker         content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
1065*d9f75844SAndroid Build Coastguard Worker   } else if (!content_desc->cryptos().empty()) {
1066*d9f75844SAndroid Build Coastguard Worker     sdes_transport = CreateSdesTransport(
1067*d9f75844SAndroid Build Coastguard Worker         content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
1068*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Creating SdesTransport.";
1069*d9f75844SAndroid Build Coastguard Worker   } else {
1070*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Creating DtlsSrtpTransport.";
1071*d9f75844SAndroid Build Coastguard Worker     dtls_srtp_transport = CreateDtlsSrtpTransport(
1072*d9f75844SAndroid Build Coastguard Worker         content_info.name, rtp_dtls_transport.get(), rtcp_dtls_transport.get());
1073*d9f75844SAndroid Build Coastguard Worker   }
1074*d9f75844SAndroid Build Coastguard Worker 
1075*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::SctpTransportInternal> sctp_transport;
1076*d9f75844SAndroid Build Coastguard Worker   if (config_.sctp_factory) {
1077*d9f75844SAndroid Build Coastguard Worker     sctp_transport =
1078*d9f75844SAndroid Build Coastguard Worker         config_.sctp_factory->CreateSctpTransport(rtp_dtls_transport.get());
1079*d9f75844SAndroid Build Coastguard Worker   }
1080*d9f75844SAndroid Build Coastguard Worker 
1081*d9f75844SAndroid Build Coastguard Worker   std::unique_ptr<cricket::JsepTransport> jsep_transport =
1082*d9f75844SAndroid Build Coastguard Worker       std::make_unique<cricket::JsepTransport>(
1083*d9f75844SAndroid Build Coastguard Worker           content_info.name, certificate_, std::move(ice), std::move(rtcp_ice),
1084*d9f75844SAndroid Build Coastguard Worker           std::move(unencrypted_rtp_transport), std::move(sdes_transport),
1085*d9f75844SAndroid Build Coastguard Worker           std::move(dtls_srtp_transport), std::move(rtp_dtls_transport),
1086*d9f75844SAndroid Build Coastguard Worker           std::move(rtcp_dtls_transport), std::move(sctp_transport), [&]() {
1087*d9f75844SAndroid Build Coastguard Worker             RTC_DCHECK_RUN_ON(network_thread_);
1088*d9f75844SAndroid Build Coastguard Worker             UpdateAggregateStates_n();
1089*d9f75844SAndroid Build Coastguard Worker           });
1090*d9f75844SAndroid Build Coastguard Worker 
1091*d9f75844SAndroid Build Coastguard Worker   jsep_transport->rtp_transport()->SignalRtcpPacketReceived.connect(
1092*d9f75844SAndroid Build Coastguard Worker       this, &JsepTransportController::OnRtcpPacketReceived_n);
1093*d9f75844SAndroid Build Coastguard Worker 
1094*d9f75844SAndroid Build Coastguard Worker   transports_.RegisterTransport(content_info.name, std::move(jsep_transport));
1095*d9f75844SAndroid Build Coastguard Worker   UpdateAggregateStates_n();
1096*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
1097*d9f75844SAndroid Build Coastguard Worker }
1098*d9f75844SAndroid Build Coastguard Worker 
DestroyAllJsepTransports_n()1099*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::DestroyAllJsepTransports_n() {
1100*d9f75844SAndroid Build Coastguard Worker   transports_.DestroyAllTransports();
1101*d9f75844SAndroid Build Coastguard Worker }
1102*d9f75844SAndroid Build Coastguard Worker 
SetIceRole_n(cricket::IceRole ice_role)1103*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::SetIceRole_n(cricket::IceRole ice_role) {
1104*d9f75844SAndroid Build Coastguard Worker   ice_role_ = ice_role;
1105*d9f75844SAndroid Build Coastguard Worker   auto dtls_transports = GetDtlsTransports();
1106*d9f75844SAndroid Build Coastguard Worker   for (auto& dtls : dtls_transports) {
1107*d9f75844SAndroid Build Coastguard Worker     dtls->ice_transport()->SetIceRole(ice_role_);
1108*d9f75844SAndroid Build Coastguard Worker   }
1109*d9f75844SAndroid Build Coastguard Worker }
1110*d9f75844SAndroid Build Coastguard Worker 
DetermineIceRole(cricket::JsepTransport * jsep_transport,const cricket::TransportInfo & transport_info,SdpType type,bool local)1111*d9f75844SAndroid Build Coastguard Worker cricket::IceRole JsepTransportController::DetermineIceRole(
1112*d9f75844SAndroid Build Coastguard Worker     cricket::JsepTransport* jsep_transport,
1113*d9f75844SAndroid Build Coastguard Worker     const cricket::TransportInfo& transport_info,
1114*d9f75844SAndroid Build Coastguard Worker     SdpType type,
1115*d9f75844SAndroid Build Coastguard Worker     bool local) {
1116*d9f75844SAndroid Build Coastguard Worker   cricket::IceRole ice_role = ice_role_;
1117*d9f75844SAndroid Build Coastguard Worker   auto tdesc = transport_info.description;
1118*d9f75844SAndroid Build Coastguard Worker   if (local) {
1119*d9f75844SAndroid Build Coastguard Worker     // The initial offer side may use ICE Lite, in which case, per RFC5245
1120*d9f75844SAndroid Build Coastguard Worker     // Section 5.1.1, the answer side should take the controlling role if it is
1121*d9f75844SAndroid Build Coastguard Worker     // in the full ICE mode.
1122*d9f75844SAndroid Build Coastguard Worker     //
1123*d9f75844SAndroid Build Coastguard Worker     // When both sides use ICE Lite, the initial offer side must take the
1124*d9f75844SAndroid Build Coastguard Worker     // controlling role, and this is the default logic implemented in
1125*d9f75844SAndroid Build Coastguard Worker     // SetLocalDescription in JsepTransportController.
1126*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport->remote_description() &&
1127*d9f75844SAndroid Build Coastguard Worker         jsep_transport->remote_description()->transport_desc.ice_mode ==
1128*d9f75844SAndroid Build Coastguard Worker             cricket::ICEMODE_LITE &&
1129*d9f75844SAndroid Build Coastguard Worker         ice_role_ == cricket::ICEROLE_CONTROLLED &&
1130*d9f75844SAndroid Build Coastguard Worker         tdesc.ice_mode == cricket::ICEMODE_FULL) {
1131*d9f75844SAndroid Build Coastguard Worker       ice_role = cricket::ICEROLE_CONTROLLING;
1132*d9f75844SAndroid Build Coastguard Worker     }
1133*d9f75844SAndroid Build Coastguard Worker   } else {
1134*d9f75844SAndroid Build Coastguard Worker     // If our role is cricket::ICEROLE_CONTROLLED and the remote endpoint
1135*d9f75844SAndroid Build Coastguard Worker     // supports only ice_lite, this local endpoint should take the CONTROLLING
1136*d9f75844SAndroid Build Coastguard Worker     // role.
1137*d9f75844SAndroid Build Coastguard Worker     // TODO(deadbeef): This is a session-level attribute, so it really shouldn't
1138*d9f75844SAndroid Build Coastguard Worker     // be in a TransportDescription in the first place...
1139*d9f75844SAndroid Build Coastguard Worker     if (ice_role_ == cricket::ICEROLE_CONTROLLED &&
1140*d9f75844SAndroid Build Coastguard Worker         tdesc.ice_mode == cricket::ICEMODE_LITE) {
1141*d9f75844SAndroid Build Coastguard Worker       ice_role = cricket::ICEROLE_CONTROLLING;
1142*d9f75844SAndroid Build Coastguard Worker     }
1143*d9f75844SAndroid Build Coastguard Worker 
1144*d9f75844SAndroid Build Coastguard Worker     // If we use ICE Lite and the remote endpoint uses the full implementation
1145*d9f75844SAndroid Build Coastguard Worker     // of ICE, the local endpoint must take the controlled role, and the other
1146*d9f75844SAndroid Build Coastguard Worker     // side must be the controlling role.
1147*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport->local_description() &&
1148*d9f75844SAndroid Build Coastguard Worker         jsep_transport->local_description()->transport_desc.ice_mode ==
1149*d9f75844SAndroid Build Coastguard Worker             cricket::ICEMODE_LITE &&
1150*d9f75844SAndroid Build Coastguard Worker         ice_role_ == cricket::ICEROLE_CONTROLLING &&
1151*d9f75844SAndroid Build Coastguard Worker         tdesc.ice_mode == cricket::ICEMODE_FULL) {
1152*d9f75844SAndroid Build Coastguard Worker       ice_role = cricket::ICEROLE_CONTROLLED;
1153*d9f75844SAndroid Build Coastguard Worker     }
1154*d9f75844SAndroid Build Coastguard Worker   }
1155*d9f75844SAndroid Build Coastguard Worker 
1156*d9f75844SAndroid Build Coastguard Worker   return ice_role;
1157*d9f75844SAndroid Build Coastguard Worker }
1158*d9f75844SAndroid Build Coastguard Worker 
OnTransportWritableState_n(rtc::PacketTransportInternal * transport)1159*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportWritableState_n(
1160*d9f75844SAndroid Build Coastguard Worker     rtc::PacketTransportInternal* transport) {
1161*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << " Transport " << transport->transport_name()
1162*d9f75844SAndroid Build Coastguard Worker                    << " writability changed to " << transport->writable()
1163*d9f75844SAndroid Build Coastguard Worker                    << ".";
1164*d9f75844SAndroid Build Coastguard Worker   UpdateAggregateStates_n();
1165*d9f75844SAndroid Build Coastguard Worker }
1166*d9f75844SAndroid Build Coastguard Worker 
OnTransportReceivingState_n(rtc::PacketTransportInternal * transport)1167*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportReceivingState_n(
1168*d9f75844SAndroid Build Coastguard Worker     rtc::PacketTransportInternal* transport) {
1169*d9f75844SAndroid Build Coastguard Worker   UpdateAggregateStates_n();
1170*d9f75844SAndroid Build Coastguard Worker }
1171*d9f75844SAndroid Build Coastguard Worker 
OnTransportGatheringState_n(cricket::IceTransportInternal * transport)1172*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportGatheringState_n(
1173*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* transport) {
1174*d9f75844SAndroid Build Coastguard Worker   UpdateAggregateStates_n();
1175*d9f75844SAndroid Build Coastguard Worker }
1176*d9f75844SAndroid Build Coastguard Worker 
OnTransportCandidateGathered_n(cricket::IceTransportInternal * transport,const cricket::Candidate & candidate)1177*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportCandidateGathered_n(
1178*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* transport,
1179*d9f75844SAndroid Build Coastguard Worker     const cricket::Candidate& candidate) {
1180*d9f75844SAndroid Build Coastguard Worker   // We should never signal peer-reflexive candidates.
1181*d9f75844SAndroid Build Coastguard Worker   if (candidate.type() == cricket::PRFLX_PORT_TYPE) {
1182*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_NOTREACHED();
1183*d9f75844SAndroid Build Coastguard Worker     return;
1184*d9f75844SAndroid Build Coastguard Worker   }
1185*d9f75844SAndroid Build Coastguard Worker 
1186*d9f75844SAndroid Build Coastguard Worker   signal_ice_candidates_gathered_.Send(
1187*d9f75844SAndroid Build Coastguard Worker       transport->transport_name(), std::vector<cricket::Candidate>{candidate});
1188*d9f75844SAndroid Build Coastguard Worker }
1189*d9f75844SAndroid Build Coastguard Worker 
OnTransportCandidateError_n(cricket::IceTransportInternal * transport,const cricket::IceCandidateErrorEvent & event)1190*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportCandidateError_n(
1191*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* transport,
1192*d9f75844SAndroid Build Coastguard Worker     const cricket::IceCandidateErrorEvent& event) {
1193*d9f75844SAndroid Build Coastguard Worker   signal_ice_candidate_error_.Send(event);
1194*d9f75844SAndroid Build Coastguard Worker }
OnTransportCandidatesRemoved_n(cricket::IceTransportInternal * transport,const cricket::Candidates & candidates)1195*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportCandidatesRemoved_n(
1196*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* transport,
1197*d9f75844SAndroid Build Coastguard Worker     const cricket::Candidates& candidates) {
1198*d9f75844SAndroid Build Coastguard Worker   signal_ice_candidates_removed_.Send(candidates);
1199*d9f75844SAndroid Build Coastguard Worker }
OnTransportCandidatePairChanged_n(const cricket::CandidatePairChangeEvent & event)1200*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportCandidatePairChanged_n(
1201*d9f75844SAndroid Build Coastguard Worker     const cricket::CandidatePairChangeEvent& event) {
1202*d9f75844SAndroid Build Coastguard Worker   signal_ice_candidate_pair_changed_.Send(event);
1203*d9f75844SAndroid Build Coastguard Worker }
1204*d9f75844SAndroid Build Coastguard Worker 
OnTransportRoleConflict_n(cricket::IceTransportInternal * transport)1205*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportRoleConflict_n(
1206*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* transport) {
1207*d9f75844SAndroid Build Coastguard Worker   // Note: since the role conflict is handled entirely on the network thread,
1208*d9f75844SAndroid Build Coastguard Worker   // we don't need to worry about role conflicts occurring on two ports at
1209*d9f75844SAndroid Build Coastguard Worker   // once. The first one encountered should immediately reverse the role.
1210*d9f75844SAndroid Build Coastguard Worker   cricket::IceRole reversed_role = (ice_role_ == cricket::ICEROLE_CONTROLLING)
1211*d9f75844SAndroid Build Coastguard Worker                                        ? cricket::ICEROLE_CONTROLLED
1212*d9f75844SAndroid Build Coastguard Worker                                        : cricket::ICEROLE_CONTROLLING;
1213*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "Got role conflict; switching to "
1214*d9f75844SAndroid Build Coastguard Worker                    << (reversed_role == cricket::ICEROLE_CONTROLLING
1215*d9f75844SAndroid Build Coastguard Worker                            ? "controlling"
1216*d9f75844SAndroid Build Coastguard Worker                            : "controlled")
1217*d9f75844SAndroid Build Coastguard Worker                    << " role.";
1218*d9f75844SAndroid Build Coastguard Worker   SetIceRole_n(reversed_role);
1219*d9f75844SAndroid Build Coastguard Worker }
1220*d9f75844SAndroid Build Coastguard Worker 
OnTransportStateChanged_n(cricket::IceTransportInternal * transport)1221*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnTransportStateChanged_n(
1222*d9f75844SAndroid Build Coastguard Worker     cricket::IceTransportInternal* transport) {
1223*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << transport->transport_name() << " Transport "
1224*d9f75844SAndroid Build Coastguard Worker                    << transport->component()
1225*d9f75844SAndroid Build Coastguard Worker                    << " state changed. Check if state is complete.";
1226*d9f75844SAndroid Build Coastguard Worker   UpdateAggregateStates_n();
1227*d9f75844SAndroid Build Coastguard Worker }
1228*d9f75844SAndroid Build Coastguard Worker 
UpdateAggregateStates_n()1229*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::UpdateAggregateStates_n() {
1230*d9f75844SAndroid Build Coastguard Worker   TRACE_EVENT0("webrtc", "JsepTransportController::UpdateAggregateStates_n");
1231*d9f75844SAndroid Build Coastguard Worker   auto dtls_transports = GetActiveDtlsTransports();
1232*d9f75844SAndroid Build Coastguard Worker   cricket::IceConnectionState new_connection_state =
1233*d9f75844SAndroid Build Coastguard Worker       cricket::kIceConnectionConnecting;
1234*d9f75844SAndroid Build Coastguard Worker   PeerConnectionInterface::IceConnectionState new_ice_connection_state =
1235*d9f75844SAndroid Build Coastguard Worker       PeerConnectionInterface::IceConnectionState::kIceConnectionNew;
1236*d9f75844SAndroid Build Coastguard Worker   PeerConnectionInterface::PeerConnectionState new_combined_state =
1237*d9f75844SAndroid Build Coastguard Worker       PeerConnectionInterface::PeerConnectionState::kNew;
1238*d9f75844SAndroid Build Coastguard Worker   cricket::IceGatheringState new_gathering_state = cricket::kIceGatheringNew;
1239*d9f75844SAndroid Build Coastguard Worker   bool any_failed = false;
1240*d9f75844SAndroid Build Coastguard Worker   bool all_connected = !dtls_transports.empty();
1241*d9f75844SAndroid Build Coastguard Worker   bool all_completed = !dtls_transports.empty();
1242*d9f75844SAndroid Build Coastguard Worker   bool any_gathering = false;
1243*d9f75844SAndroid Build Coastguard Worker   bool all_done_gathering = !dtls_transports.empty();
1244*d9f75844SAndroid Build Coastguard Worker 
1245*d9f75844SAndroid Build Coastguard Worker   std::map<IceTransportState, int> ice_state_counts;
1246*d9f75844SAndroid Build Coastguard Worker   std::map<DtlsTransportState, int> dtls_state_counts;
1247*d9f75844SAndroid Build Coastguard Worker 
1248*d9f75844SAndroid Build Coastguard Worker   for (const auto& dtls : dtls_transports) {
1249*d9f75844SAndroid Build Coastguard Worker     any_failed = any_failed || dtls->ice_transport()->GetState() ==
1250*d9f75844SAndroid Build Coastguard Worker                                    cricket::IceTransportState::STATE_FAILED;
1251*d9f75844SAndroid Build Coastguard Worker     all_connected = all_connected && dtls->writable();
1252*d9f75844SAndroid Build Coastguard Worker     all_completed =
1253*d9f75844SAndroid Build Coastguard Worker         all_completed && dtls->writable() &&
1254*d9f75844SAndroid Build Coastguard Worker         dtls->ice_transport()->GetState() ==
1255*d9f75844SAndroid Build Coastguard Worker             cricket::IceTransportState::STATE_COMPLETED &&
1256*d9f75844SAndroid Build Coastguard Worker         dtls->ice_transport()->GetIceRole() == cricket::ICEROLE_CONTROLLING &&
1257*d9f75844SAndroid Build Coastguard Worker         dtls->ice_transport()->gathering_state() ==
1258*d9f75844SAndroid Build Coastguard Worker             cricket::kIceGatheringComplete;
1259*d9f75844SAndroid Build Coastguard Worker     any_gathering = any_gathering || dtls->ice_transport()->gathering_state() !=
1260*d9f75844SAndroid Build Coastguard Worker                                          cricket::kIceGatheringNew;
1261*d9f75844SAndroid Build Coastguard Worker     all_done_gathering =
1262*d9f75844SAndroid Build Coastguard Worker         all_done_gathering && dtls->ice_transport()->gathering_state() ==
1263*d9f75844SAndroid Build Coastguard Worker                                   cricket::kIceGatheringComplete;
1264*d9f75844SAndroid Build Coastguard Worker 
1265*d9f75844SAndroid Build Coastguard Worker     dtls_state_counts[dtls->dtls_state()]++;
1266*d9f75844SAndroid Build Coastguard Worker     ice_state_counts[dtls->ice_transport()->GetIceTransportState()]++;
1267*d9f75844SAndroid Build Coastguard Worker   }
1268*d9f75844SAndroid Build Coastguard Worker 
1269*d9f75844SAndroid Build Coastguard Worker   if (any_failed) {
1270*d9f75844SAndroid Build Coastguard Worker     new_connection_state = cricket::kIceConnectionFailed;
1271*d9f75844SAndroid Build Coastguard Worker   } else if (all_completed) {
1272*d9f75844SAndroid Build Coastguard Worker     new_connection_state = cricket::kIceConnectionCompleted;
1273*d9f75844SAndroid Build Coastguard Worker   } else if (all_connected) {
1274*d9f75844SAndroid Build Coastguard Worker     new_connection_state = cricket::kIceConnectionConnected;
1275*d9f75844SAndroid Build Coastguard Worker   }
1276*d9f75844SAndroid Build Coastguard Worker   if (ice_connection_state_ != new_connection_state) {
1277*d9f75844SAndroid Build Coastguard Worker     ice_connection_state_ = new_connection_state;
1278*d9f75844SAndroid Build Coastguard Worker 
1279*d9f75844SAndroid Build Coastguard Worker     signal_ice_connection_state_.Send(new_connection_state);
1280*d9f75844SAndroid Build Coastguard Worker   }
1281*d9f75844SAndroid Build Coastguard Worker 
1282*d9f75844SAndroid Build Coastguard Worker   // Compute the current RTCIceConnectionState as described in
1283*d9f75844SAndroid Build Coastguard Worker   // https://www.w3.org/TR/webrtc/#dom-rtciceconnectionstate.
1284*d9f75844SAndroid Build Coastguard Worker   // The PeerConnection is responsible for handling the "closed" state.
1285*d9f75844SAndroid Build Coastguard Worker   int total_ice_checking = ice_state_counts[IceTransportState::kChecking];
1286*d9f75844SAndroid Build Coastguard Worker   int total_ice_connected = ice_state_counts[IceTransportState::kConnected];
1287*d9f75844SAndroid Build Coastguard Worker   int total_ice_completed = ice_state_counts[IceTransportState::kCompleted];
1288*d9f75844SAndroid Build Coastguard Worker   int total_ice_failed = ice_state_counts[IceTransportState::kFailed];
1289*d9f75844SAndroid Build Coastguard Worker   int total_ice_disconnected =
1290*d9f75844SAndroid Build Coastguard Worker       ice_state_counts[IceTransportState::kDisconnected];
1291*d9f75844SAndroid Build Coastguard Worker   int total_ice_closed = ice_state_counts[IceTransportState::kClosed];
1292*d9f75844SAndroid Build Coastguard Worker   int total_ice_new = ice_state_counts[IceTransportState::kNew];
1293*d9f75844SAndroid Build Coastguard Worker   int total_ice = dtls_transports.size();
1294*d9f75844SAndroid Build Coastguard Worker 
1295*d9f75844SAndroid Build Coastguard Worker   if (total_ice_failed > 0) {
1296*d9f75844SAndroid Build Coastguard Worker     // Any RTCIceTransports are in the "failed" state.
1297*d9f75844SAndroid Build Coastguard Worker     new_ice_connection_state = PeerConnectionInterface::kIceConnectionFailed;
1298*d9f75844SAndroid Build Coastguard Worker   } else if (total_ice_disconnected > 0) {
1299*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and any RTCIceTransports are in the
1300*d9f75844SAndroid Build Coastguard Worker     // "disconnected" state.
1301*d9f75844SAndroid Build Coastguard Worker     new_ice_connection_state =
1302*d9f75844SAndroid Build Coastguard Worker         PeerConnectionInterface::kIceConnectionDisconnected;
1303*d9f75844SAndroid Build Coastguard Worker   } else if (total_ice_new + total_ice_closed == total_ice) {
1304*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and all RTCIceTransports are in the
1305*d9f75844SAndroid Build Coastguard Worker     // "new" or "closed" state, or there are no transports.
1306*d9f75844SAndroid Build Coastguard Worker     new_ice_connection_state = PeerConnectionInterface::kIceConnectionNew;
1307*d9f75844SAndroid Build Coastguard Worker   } else if (total_ice_new + total_ice_checking > 0) {
1308*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and any RTCIceTransports are in the
1309*d9f75844SAndroid Build Coastguard Worker     // "new" or "checking" state.
1310*d9f75844SAndroid Build Coastguard Worker     new_ice_connection_state = PeerConnectionInterface::kIceConnectionChecking;
1311*d9f75844SAndroid Build Coastguard Worker   } else if (total_ice_completed + total_ice_closed == total_ice ||
1312*d9f75844SAndroid Build Coastguard Worker              all_completed) {
1313*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and all RTCIceTransports are in the
1314*d9f75844SAndroid Build Coastguard Worker     // "completed" or "closed" state.
1315*d9f75844SAndroid Build Coastguard Worker     //
1316*d9f75844SAndroid Build Coastguard Worker     // TODO(https://bugs.webrtc.org/10356): The all_completed condition is added
1317*d9f75844SAndroid Build Coastguard Worker     // to mimic the behavior of the old ICE connection state, and should be
1318*d9f75844SAndroid Build Coastguard Worker     // removed once we get end-of-candidates signaling in place.
1319*d9f75844SAndroid Build Coastguard Worker     new_ice_connection_state = PeerConnectionInterface::kIceConnectionCompleted;
1320*d9f75844SAndroid Build Coastguard Worker   } else if (total_ice_connected + total_ice_completed + total_ice_closed ==
1321*d9f75844SAndroid Build Coastguard Worker              total_ice) {
1322*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and all RTCIceTransports are in the
1323*d9f75844SAndroid Build Coastguard Worker     // "connected", "completed" or "closed" state.
1324*d9f75844SAndroid Build Coastguard Worker     new_ice_connection_state = PeerConnectionInterface::kIceConnectionConnected;
1325*d9f75844SAndroid Build Coastguard Worker   } else {
1326*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_NOTREACHED();
1327*d9f75844SAndroid Build Coastguard Worker   }
1328*d9f75844SAndroid Build Coastguard Worker 
1329*d9f75844SAndroid Build Coastguard Worker   if (standardized_ice_connection_state_ != new_ice_connection_state) {
1330*d9f75844SAndroid Build Coastguard Worker     if (standardized_ice_connection_state_ ==
1331*d9f75844SAndroid Build Coastguard Worker             PeerConnectionInterface::kIceConnectionChecking &&
1332*d9f75844SAndroid Build Coastguard Worker         new_ice_connection_state ==
1333*d9f75844SAndroid Build Coastguard Worker             PeerConnectionInterface::kIceConnectionCompleted) {
1334*d9f75844SAndroid Build Coastguard Worker       // Ensure that we never skip over the "connected" state.
1335*d9f75844SAndroid Build Coastguard Worker       signal_standardized_ice_connection_state_.Send(
1336*d9f75844SAndroid Build Coastguard Worker           PeerConnectionInterface::kIceConnectionConnected);
1337*d9f75844SAndroid Build Coastguard Worker     }
1338*d9f75844SAndroid Build Coastguard Worker     standardized_ice_connection_state_ = new_ice_connection_state;
1339*d9f75844SAndroid Build Coastguard Worker     signal_standardized_ice_connection_state_.Send(new_ice_connection_state);
1340*d9f75844SAndroid Build Coastguard Worker   }
1341*d9f75844SAndroid Build Coastguard Worker 
1342*d9f75844SAndroid Build Coastguard Worker   // Compute the current RTCPeerConnectionState as described in
1343*d9f75844SAndroid Build Coastguard Worker   // https://www.w3.org/TR/webrtc/#dom-rtcpeerconnectionstate.
1344*d9f75844SAndroid Build Coastguard Worker   // The PeerConnection is responsible for handling the "closed" state.
1345*d9f75844SAndroid Build Coastguard Worker   // Note that "connecting" is only a valid state for DTLS transports while
1346*d9f75844SAndroid Build Coastguard Worker   // "checking", "completed" and "disconnected" are only valid for ICE
1347*d9f75844SAndroid Build Coastguard Worker   // transports.
1348*d9f75844SAndroid Build Coastguard Worker   int total_connected =
1349*d9f75844SAndroid Build Coastguard Worker       total_ice_connected + dtls_state_counts[DtlsTransportState::kConnected];
1350*d9f75844SAndroid Build Coastguard Worker   int total_dtls_connecting =
1351*d9f75844SAndroid Build Coastguard Worker       dtls_state_counts[DtlsTransportState::kConnecting];
1352*d9f75844SAndroid Build Coastguard Worker   int total_failed =
1353*d9f75844SAndroid Build Coastguard Worker       total_ice_failed + dtls_state_counts[DtlsTransportState::kFailed];
1354*d9f75844SAndroid Build Coastguard Worker   int total_closed =
1355*d9f75844SAndroid Build Coastguard Worker       total_ice_closed + dtls_state_counts[DtlsTransportState::kClosed];
1356*d9f75844SAndroid Build Coastguard Worker   int total_new = total_ice_new + dtls_state_counts[DtlsTransportState::kNew];
1357*d9f75844SAndroid Build Coastguard Worker   int total_transports = total_ice * 2;
1358*d9f75844SAndroid Build Coastguard Worker 
1359*d9f75844SAndroid Build Coastguard Worker   if (total_failed > 0) {
1360*d9f75844SAndroid Build Coastguard Worker     // Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
1361*d9f75844SAndroid Build Coastguard Worker     new_combined_state = PeerConnectionInterface::PeerConnectionState::kFailed;
1362*d9f75844SAndroid Build Coastguard Worker   } else if (total_ice_disconnected > 0) {
1363*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and any RTCIceTransports or
1364*d9f75844SAndroid Build Coastguard Worker     // RTCDtlsTransports are in the "disconnected" state.
1365*d9f75844SAndroid Build Coastguard Worker     new_combined_state =
1366*d9f75844SAndroid Build Coastguard Worker         PeerConnectionInterface::PeerConnectionState::kDisconnected;
1367*d9f75844SAndroid Build Coastguard Worker   } else if (total_new + total_closed == total_transports) {
1368*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and all RTCIceTransports and
1369*d9f75844SAndroid Build Coastguard Worker     // RTCDtlsTransports are in the "new" or "closed" state, or there are no
1370*d9f75844SAndroid Build Coastguard Worker     // transports.
1371*d9f75844SAndroid Build Coastguard Worker     new_combined_state = PeerConnectionInterface::PeerConnectionState::kNew;
1372*d9f75844SAndroid Build Coastguard Worker   } else if (total_new + total_dtls_connecting + total_ice_checking > 0) {
1373*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and all RTCIceTransports or
1374*d9f75844SAndroid Build Coastguard Worker     // RTCDtlsTransports are in the "new", "connecting" or "checking" state.
1375*d9f75844SAndroid Build Coastguard Worker     new_combined_state =
1376*d9f75844SAndroid Build Coastguard Worker         PeerConnectionInterface::PeerConnectionState::kConnecting;
1377*d9f75844SAndroid Build Coastguard Worker   } else if (total_connected + total_ice_completed + total_closed ==
1378*d9f75844SAndroid Build Coastguard Worker              total_transports) {
1379*d9f75844SAndroid Build Coastguard Worker     // None of the previous states apply and all RTCIceTransports and
1380*d9f75844SAndroid Build Coastguard Worker     // RTCDtlsTransports are in the "connected", "completed" or "closed" state.
1381*d9f75844SAndroid Build Coastguard Worker     new_combined_state =
1382*d9f75844SAndroid Build Coastguard Worker         PeerConnectionInterface::PeerConnectionState::kConnected;
1383*d9f75844SAndroid Build Coastguard Worker   } else {
1384*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_NOTREACHED();
1385*d9f75844SAndroid Build Coastguard Worker   }
1386*d9f75844SAndroid Build Coastguard Worker 
1387*d9f75844SAndroid Build Coastguard Worker   if (combined_connection_state_ != new_combined_state) {
1388*d9f75844SAndroid Build Coastguard Worker     combined_connection_state_ = new_combined_state;
1389*d9f75844SAndroid Build Coastguard Worker     signal_connection_state_.Send(new_combined_state);
1390*d9f75844SAndroid Build Coastguard Worker   }
1391*d9f75844SAndroid Build Coastguard Worker 
1392*d9f75844SAndroid Build Coastguard Worker   // Compute the gathering state.
1393*d9f75844SAndroid Build Coastguard Worker   if (dtls_transports.empty()) {
1394*d9f75844SAndroid Build Coastguard Worker     new_gathering_state = cricket::kIceGatheringNew;
1395*d9f75844SAndroid Build Coastguard Worker   } else if (all_done_gathering) {
1396*d9f75844SAndroid Build Coastguard Worker     new_gathering_state = cricket::kIceGatheringComplete;
1397*d9f75844SAndroid Build Coastguard Worker   } else if (any_gathering) {
1398*d9f75844SAndroid Build Coastguard Worker     new_gathering_state = cricket::kIceGatheringGathering;
1399*d9f75844SAndroid Build Coastguard Worker   }
1400*d9f75844SAndroid Build Coastguard Worker   if (ice_gathering_state_ != new_gathering_state) {
1401*d9f75844SAndroid Build Coastguard Worker     ice_gathering_state_ = new_gathering_state;
1402*d9f75844SAndroid Build Coastguard Worker     signal_ice_gathering_state_.Send(new_gathering_state);
1403*d9f75844SAndroid Build Coastguard Worker   }
1404*d9f75844SAndroid Build Coastguard Worker }
1405*d9f75844SAndroid Build Coastguard Worker 
OnRtcpPacketReceived_n(rtc::CopyOnWriteBuffer * packet,int64_t packet_time_us)1406*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnRtcpPacketReceived_n(
1407*d9f75844SAndroid Build Coastguard Worker     rtc::CopyOnWriteBuffer* packet,
1408*d9f75844SAndroid Build Coastguard Worker     int64_t packet_time_us) {
1409*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(config_.rtcp_handler);
1410*d9f75844SAndroid Build Coastguard Worker   config_.rtcp_handler(*packet, packet_time_us);
1411*d9f75844SAndroid Build Coastguard Worker }
1412*d9f75844SAndroid Build Coastguard Worker 
OnDtlsHandshakeError(rtc::SSLHandshakeError error)1413*d9f75844SAndroid Build Coastguard Worker void JsepTransportController::OnDtlsHandshakeError(
1414*d9f75844SAndroid Build Coastguard Worker     rtc::SSLHandshakeError error) {
1415*d9f75844SAndroid Build Coastguard Worker   config_.on_dtls_handshake_error_(error);
1416*d9f75844SAndroid Build Coastguard Worker }
1417*d9f75844SAndroid Build Coastguard Worker 
OnTransportChanged(const std::string & mid,cricket::JsepTransport * jsep_transport)1418*d9f75844SAndroid Build Coastguard Worker bool JsepTransportController::OnTransportChanged(
1419*d9f75844SAndroid Build Coastguard Worker     const std::string& mid,
1420*d9f75844SAndroid Build Coastguard Worker     cricket::JsepTransport* jsep_transport) {
1421*d9f75844SAndroid Build Coastguard Worker   if (config_.transport_observer) {
1422*d9f75844SAndroid Build Coastguard Worker     if (jsep_transport) {
1423*d9f75844SAndroid Build Coastguard Worker       return config_.transport_observer->OnTransportChanged(
1424*d9f75844SAndroid Build Coastguard Worker           mid, jsep_transport->rtp_transport(),
1425*d9f75844SAndroid Build Coastguard Worker           jsep_transport->RtpDtlsTransport(),
1426*d9f75844SAndroid Build Coastguard Worker           jsep_transport->data_channel_transport());
1427*d9f75844SAndroid Build Coastguard Worker     } else {
1428*d9f75844SAndroid Build Coastguard Worker       return config_.transport_observer->OnTransportChanged(mid, nullptr,
1429*d9f75844SAndroid Build Coastguard Worker                                                             nullptr, nullptr);
1430*d9f75844SAndroid Build Coastguard Worker     }
1431*d9f75844SAndroid Build Coastguard Worker   }
1432*d9f75844SAndroid Build Coastguard Worker   return false;
1433*d9f75844SAndroid Build Coastguard Worker }
1434*d9f75844SAndroid Build Coastguard Worker 
1435*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
1436