1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2021 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_collection.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <map>
15*d9f75844SAndroid Build Coastguard Worker #include <set>
16*d9f75844SAndroid Build Coastguard Worker #include <type_traits>
17*d9f75844SAndroid Build Coastguard Worker #include <utility>
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/p2p_constants.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
21*d9f75844SAndroid Build Coastguard Worker
22*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
23*d9f75844SAndroid Build Coastguard Worker
Update(const cricket::SessionDescription * description,SdpType type)24*d9f75844SAndroid Build Coastguard Worker void BundleManager::Update(const cricket::SessionDescription* description,
25*d9f75844SAndroid Build Coastguard Worker SdpType type) {
26*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
27*d9f75844SAndroid Build Coastguard Worker // Rollbacks should call Rollback, not Update.
28*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(type != SdpType::kRollback);
29*d9f75844SAndroid Build Coastguard Worker bool bundle_groups_changed = false;
30*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/3349): Do this for kPrAnswer as well. To make this
31*d9f75844SAndroid Build Coastguard Worker // work, we also need to make sure PRANSWERs don't call
32*d9f75844SAndroid Build Coastguard Worker // MaybeDestroyJsepTransport, because the final answer may need the destroyed
33*d9f75844SAndroid Build Coastguard Worker // transport if it changes the BUNDLE group.
34*d9f75844SAndroid Build Coastguard Worker if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle ||
35*d9f75844SAndroid Build Coastguard Worker type == SdpType::kAnswer) {
36*d9f75844SAndroid Build Coastguard Worker // If our policy is "max-bundle" or this is an answer, update all bundle
37*d9f75844SAndroid Build Coastguard Worker // groups.
38*d9f75844SAndroid Build Coastguard Worker bundle_groups_changed = true;
39*d9f75844SAndroid Build Coastguard Worker bundle_groups_.clear();
40*d9f75844SAndroid Build Coastguard Worker for (const cricket::ContentGroup* new_bundle_group :
41*d9f75844SAndroid Build Coastguard Worker description->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE)) {
42*d9f75844SAndroid Build Coastguard Worker bundle_groups_.push_back(
43*d9f75844SAndroid Build Coastguard Worker std::make_unique<cricket::ContentGroup>(*new_bundle_group));
44*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << "Establishing bundle group "
45*d9f75844SAndroid Build Coastguard Worker << new_bundle_group->ToString();
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker } else if (type == SdpType::kOffer) {
48*d9f75844SAndroid Build Coastguard Worker // If this is an offer, update existing bundle groups.
49*d9f75844SAndroid Build Coastguard Worker // We do this because as per RFC 8843, section 7.3.2, the answerer cannot
50*d9f75844SAndroid Build Coastguard Worker // remove an m= section from an existing BUNDLE group without rejecting it.
51*d9f75844SAndroid Build Coastguard Worker // Thus any m= sections added to a BUNDLE group in this offer can
52*d9f75844SAndroid Build Coastguard Worker // preemptively start using the bundled transport, as there is no possible
53*d9f75844SAndroid Build Coastguard Worker // non-bundled fallback.
54*d9f75844SAndroid Build Coastguard Worker for (const cricket::ContentGroup* new_bundle_group :
55*d9f75844SAndroid Build Coastguard Worker description->GetGroupsByName(cricket::GROUP_TYPE_BUNDLE)) {
56*d9f75844SAndroid Build Coastguard Worker // Attempt to find a matching existing group.
57*d9f75844SAndroid Build Coastguard Worker for (const std::string& mid : new_bundle_group->content_names()) {
58*d9f75844SAndroid Build Coastguard Worker auto it = established_bundle_groups_by_mid_.find(mid);
59*d9f75844SAndroid Build Coastguard Worker if (it != established_bundle_groups_by_mid_.end()) {
60*d9f75844SAndroid Build Coastguard Worker *it->second = *new_bundle_group;
61*d9f75844SAndroid Build Coastguard Worker bundle_groups_changed = true;
62*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE)
63*d9f75844SAndroid Build Coastguard Worker << "Establishing bundle group " << new_bundle_group->ToString();
64*d9f75844SAndroid Build Coastguard Worker break;
65*d9f75844SAndroid Build Coastguard Worker }
66*d9f75844SAndroid Build Coastguard Worker }
67*d9f75844SAndroid Build Coastguard Worker }
68*d9f75844SAndroid Build Coastguard Worker }
69*d9f75844SAndroid Build Coastguard Worker if (bundle_groups_changed) {
70*d9f75844SAndroid Build Coastguard Worker RefreshEstablishedBundleGroupsByMid();
71*d9f75844SAndroid Build Coastguard Worker }
72*d9f75844SAndroid Build Coastguard Worker }
73*d9f75844SAndroid Build Coastguard Worker
LookupGroupByMid(const std::string & mid) const74*d9f75844SAndroid Build Coastguard Worker const cricket::ContentGroup* BundleManager::LookupGroupByMid(
75*d9f75844SAndroid Build Coastguard Worker const std::string& mid) const {
76*d9f75844SAndroid Build Coastguard Worker auto it = established_bundle_groups_by_mid_.find(mid);
77*d9f75844SAndroid Build Coastguard Worker return it != established_bundle_groups_by_mid_.end() ? it->second : nullptr;
78*d9f75844SAndroid Build Coastguard Worker }
IsFirstMidInGroup(const std::string & mid) const79*d9f75844SAndroid Build Coastguard Worker bool BundleManager::IsFirstMidInGroup(const std::string& mid) const {
80*d9f75844SAndroid Build Coastguard Worker auto group = LookupGroupByMid(mid);
81*d9f75844SAndroid Build Coastguard Worker if (!group) {
82*d9f75844SAndroid Build Coastguard Worker return true; // Unbundled MIDs are considered group leaders
83*d9f75844SAndroid Build Coastguard Worker }
84*d9f75844SAndroid Build Coastguard Worker return mid == *(group->FirstContentName());
85*d9f75844SAndroid Build Coastguard Worker }
86*d9f75844SAndroid Build Coastguard Worker
LookupGroupByMid(const std::string & mid)87*d9f75844SAndroid Build Coastguard Worker cricket::ContentGroup* BundleManager::LookupGroupByMid(const std::string& mid) {
88*d9f75844SAndroid Build Coastguard Worker auto it = established_bundle_groups_by_mid_.find(mid);
89*d9f75844SAndroid Build Coastguard Worker return it != established_bundle_groups_by_mid_.end() ? it->second : nullptr;
90*d9f75844SAndroid Build Coastguard Worker }
91*d9f75844SAndroid Build Coastguard Worker
DeleteMid(const cricket::ContentGroup * bundle_group,const std::string & mid)92*d9f75844SAndroid Build Coastguard Worker void BundleManager::DeleteMid(const cricket::ContentGroup* bundle_group,
93*d9f75844SAndroid Build Coastguard Worker const std::string& mid) {
94*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
95*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_VERBOSE) << "Deleting mid " << mid << " from bundle group "
96*d9f75844SAndroid Build Coastguard Worker << bundle_group->ToString();
97*d9f75844SAndroid Build Coastguard Worker // Remove the rejected content from the `bundle_group`.
98*d9f75844SAndroid Build Coastguard Worker // The const pointer arg is used to identify the group, we verify
99*d9f75844SAndroid Build Coastguard Worker // it before we use it to make a modification.
100*d9f75844SAndroid Build Coastguard Worker auto bundle_group_it = std::find_if(
101*d9f75844SAndroid Build Coastguard Worker bundle_groups_.begin(), bundle_groups_.end(),
102*d9f75844SAndroid Build Coastguard Worker [bundle_group](std::unique_ptr<cricket::ContentGroup>& group) {
103*d9f75844SAndroid Build Coastguard Worker return bundle_group == group.get();
104*d9f75844SAndroid Build Coastguard Worker });
105*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(bundle_group_it != bundle_groups_.end());
106*d9f75844SAndroid Build Coastguard Worker (*bundle_group_it)->RemoveContentName(mid);
107*d9f75844SAndroid Build Coastguard Worker established_bundle_groups_by_mid_.erase(
108*d9f75844SAndroid Build Coastguard Worker established_bundle_groups_by_mid_.find(mid));
109*d9f75844SAndroid Build Coastguard Worker }
110*d9f75844SAndroid Build Coastguard Worker
DeleteGroup(const cricket::ContentGroup * bundle_group)111*d9f75844SAndroid Build Coastguard Worker void BundleManager::DeleteGroup(const cricket::ContentGroup* bundle_group) {
112*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
113*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_VERBOSE) << "Deleting bundle group " << bundle_group->ToString();
114*d9f75844SAndroid Build Coastguard Worker
115*d9f75844SAndroid Build Coastguard Worker auto bundle_group_it = std::find_if(
116*d9f75844SAndroid Build Coastguard Worker bundle_groups_.begin(), bundle_groups_.end(),
117*d9f75844SAndroid Build Coastguard Worker [bundle_group](std::unique_ptr<cricket::ContentGroup>& group) {
118*d9f75844SAndroid Build Coastguard Worker return bundle_group == group.get();
119*d9f75844SAndroid Build Coastguard Worker });
120*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(bundle_group_it != bundle_groups_.end());
121*d9f75844SAndroid Build Coastguard Worker auto mid_list = (*bundle_group_it)->content_names();
122*d9f75844SAndroid Build Coastguard Worker for (const auto& content_name : mid_list) {
123*d9f75844SAndroid Build Coastguard Worker DeleteMid(bundle_group, content_name);
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker bundle_groups_.erase(bundle_group_it);
126*d9f75844SAndroid Build Coastguard Worker }
127*d9f75844SAndroid Build Coastguard Worker
Rollback()128*d9f75844SAndroid Build Coastguard Worker void BundleManager::Rollback() {
129*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
130*d9f75844SAndroid Build Coastguard Worker bundle_groups_.clear();
131*d9f75844SAndroid Build Coastguard Worker for (const auto& bundle_group : stable_bundle_groups_) {
132*d9f75844SAndroid Build Coastguard Worker bundle_groups_.push_back(
133*d9f75844SAndroid Build Coastguard Worker std::make_unique<cricket::ContentGroup>(*bundle_group));
134*d9f75844SAndroid Build Coastguard Worker }
135*d9f75844SAndroid Build Coastguard Worker RefreshEstablishedBundleGroupsByMid();
136*d9f75844SAndroid Build Coastguard Worker }
137*d9f75844SAndroid Build Coastguard Worker
Commit()138*d9f75844SAndroid Build Coastguard Worker void BundleManager::Commit() {
139*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
140*d9f75844SAndroid Build Coastguard Worker stable_bundle_groups_.clear();
141*d9f75844SAndroid Build Coastguard Worker for (const auto& bundle_group : bundle_groups_) {
142*d9f75844SAndroid Build Coastguard Worker stable_bundle_groups_.push_back(
143*d9f75844SAndroid Build Coastguard Worker std::make_unique<cricket::ContentGroup>(*bundle_group));
144*d9f75844SAndroid Build Coastguard Worker }
145*d9f75844SAndroid Build Coastguard Worker }
146*d9f75844SAndroid Build Coastguard Worker
RefreshEstablishedBundleGroupsByMid()147*d9f75844SAndroid Build Coastguard Worker void BundleManager::RefreshEstablishedBundleGroupsByMid() {
148*d9f75844SAndroid Build Coastguard Worker established_bundle_groups_by_mid_.clear();
149*d9f75844SAndroid Build Coastguard Worker for (const auto& bundle_group : bundle_groups_) {
150*d9f75844SAndroid Build Coastguard Worker for (const std::string& content_name : bundle_group->content_names()) {
151*d9f75844SAndroid Build Coastguard Worker established_bundle_groups_by_mid_[content_name] = bundle_group.get();
152*d9f75844SAndroid Build Coastguard Worker }
153*d9f75844SAndroid Build Coastguard Worker }
154*d9f75844SAndroid Build Coastguard Worker }
155*d9f75844SAndroid Build Coastguard Worker
RegisterTransport(const std::string & mid,std::unique_ptr<cricket::JsepTransport> transport)156*d9f75844SAndroid Build Coastguard Worker void JsepTransportCollection::RegisterTransport(
157*d9f75844SAndroid Build Coastguard Worker const std::string& mid,
158*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::JsepTransport> transport) {
159*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
160*d9f75844SAndroid Build Coastguard Worker SetTransportForMid(mid, transport.get());
161*d9f75844SAndroid Build Coastguard Worker jsep_transports_by_name_[mid] = std::move(transport);
162*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
163*d9f75844SAndroid Build Coastguard Worker }
164*d9f75844SAndroid Build Coastguard Worker
Transports()165*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::JsepTransport*> JsepTransportCollection::Transports() {
166*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
167*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::JsepTransport*> result;
168*d9f75844SAndroid Build Coastguard Worker for (auto& kv : jsep_transports_by_name_) {
169*d9f75844SAndroid Build Coastguard Worker result.push_back(kv.second.get());
170*d9f75844SAndroid Build Coastguard Worker }
171*d9f75844SAndroid Build Coastguard Worker return result;
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker
174*d9f75844SAndroid Build Coastguard Worker std::vector<cricket::JsepTransport*>
ActiveTransports()175*d9f75844SAndroid Build Coastguard Worker JsepTransportCollection::ActiveTransports() {
176*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
177*d9f75844SAndroid Build Coastguard Worker std::set<cricket::JsepTransport*> transports;
178*d9f75844SAndroid Build Coastguard Worker for (const auto& kv : mid_to_transport_) {
179*d9f75844SAndroid Build Coastguard Worker transports.insert(kv.second);
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker return std::vector<cricket::JsepTransport*>(transports.begin(),
182*d9f75844SAndroid Build Coastguard Worker transports.end());
183*d9f75844SAndroid Build Coastguard Worker }
184*d9f75844SAndroid Build Coastguard Worker
DestroyAllTransports()185*d9f75844SAndroid Build Coastguard Worker void JsepTransportCollection::DestroyAllTransports() {
186*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
187*d9f75844SAndroid Build Coastguard Worker for (const auto& jsep_transport : jsep_transports_by_name_) {
188*d9f75844SAndroid Build Coastguard Worker map_change_callback_(jsep_transport.first, nullptr);
189*d9f75844SAndroid Build Coastguard Worker }
190*d9f75844SAndroid Build Coastguard Worker jsep_transports_by_name_.clear();
191*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
192*d9f75844SAndroid Build Coastguard Worker }
193*d9f75844SAndroid Build Coastguard Worker
GetTransportByName(const std::string & transport_name) const194*d9f75844SAndroid Build Coastguard Worker const cricket::JsepTransport* JsepTransportCollection::GetTransportByName(
195*d9f75844SAndroid Build Coastguard Worker const std::string& transport_name) const {
196*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
197*d9f75844SAndroid Build Coastguard Worker auto it = jsep_transports_by_name_.find(transport_name);
198*d9f75844SAndroid Build Coastguard Worker return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker
GetTransportByName(const std::string & transport_name)201*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* JsepTransportCollection::GetTransportByName(
202*d9f75844SAndroid Build Coastguard Worker const std::string& transport_name) {
203*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
204*d9f75844SAndroid Build Coastguard Worker auto it = jsep_transports_by_name_.find(transport_name);
205*d9f75844SAndroid Build Coastguard Worker return (it == jsep_transports_by_name_.end()) ? nullptr : it->second.get();
206*d9f75844SAndroid Build Coastguard Worker }
207*d9f75844SAndroid Build Coastguard Worker
GetTransportForMid(const std::string & mid)208*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* JsepTransportCollection::GetTransportForMid(
209*d9f75844SAndroid Build Coastguard Worker const std::string& mid) {
210*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
211*d9f75844SAndroid Build Coastguard Worker auto it = mid_to_transport_.find(mid);
212*d9f75844SAndroid Build Coastguard Worker return it == mid_to_transport_.end() ? nullptr : it->second;
213*d9f75844SAndroid Build Coastguard Worker }
214*d9f75844SAndroid Build Coastguard Worker
GetTransportForMid(const std::string & mid) const215*d9f75844SAndroid Build Coastguard Worker const cricket::JsepTransport* JsepTransportCollection::GetTransportForMid(
216*d9f75844SAndroid Build Coastguard Worker const std::string& mid) const {
217*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
218*d9f75844SAndroid Build Coastguard Worker auto it = mid_to_transport_.find(mid);
219*d9f75844SAndroid Build Coastguard Worker return it == mid_to_transport_.end() ? nullptr : it->second;
220*d9f75844SAndroid Build Coastguard Worker }
221*d9f75844SAndroid Build Coastguard Worker
GetTransportForMid(absl::string_view mid)222*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* JsepTransportCollection::GetTransportForMid(
223*d9f75844SAndroid Build Coastguard Worker absl::string_view mid) {
224*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
225*d9f75844SAndroid Build Coastguard Worker // TODO(hta): should be a better way.
226*d9f75844SAndroid Build Coastguard Worker auto it = mid_to_transport_.find(std::string(mid));
227*d9f75844SAndroid Build Coastguard Worker return it == mid_to_transport_.end() ? nullptr : it->second;
228*d9f75844SAndroid Build Coastguard Worker }
229*d9f75844SAndroid Build Coastguard Worker
GetTransportForMid(absl::string_view mid) const230*d9f75844SAndroid Build Coastguard Worker const cricket::JsepTransport* JsepTransportCollection::GetTransportForMid(
231*d9f75844SAndroid Build Coastguard Worker absl::string_view mid) const {
232*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
233*d9f75844SAndroid Build Coastguard Worker // TODO(hta): Should be a better way
234*d9f75844SAndroid Build Coastguard Worker auto it = mid_to_transport_.find(std::string(mid));
235*d9f75844SAndroid Build Coastguard Worker return it == mid_to_transport_.end() ? nullptr : it->second;
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker
SetTransportForMid(const std::string & mid,cricket::JsepTransport * jsep_transport)238*d9f75844SAndroid Build Coastguard Worker bool JsepTransportCollection::SetTransportForMid(
239*d9f75844SAndroid Build Coastguard Worker const std::string& mid,
240*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* jsep_transport) {
241*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
242*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(jsep_transport);
243*d9f75844SAndroid Build Coastguard Worker
244*d9f75844SAndroid Build Coastguard Worker auto it = mid_to_transport_.find(mid);
245*d9f75844SAndroid Build Coastguard Worker if (it != mid_to_transport_.end() && it->second == jsep_transport)
246*d9f75844SAndroid Build Coastguard Worker return true;
247*d9f75844SAndroid Build Coastguard Worker
248*d9f75844SAndroid Build Coastguard Worker // The map_change_callback must be called before destroying the
249*d9f75844SAndroid Build Coastguard Worker // transport, because it removes references to the transport
250*d9f75844SAndroid Build Coastguard Worker // in the RTP demuxer.
251*d9f75844SAndroid Build Coastguard Worker bool result = map_change_callback_(mid, jsep_transport);
252*d9f75844SAndroid Build Coastguard Worker
253*d9f75844SAndroid Build Coastguard Worker if (it == mid_to_transport_.end()) {
254*d9f75844SAndroid Build Coastguard Worker mid_to_transport_.insert(std::make_pair(mid, jsep_transport));
255*d9f75844SAndroid Build Coastguard Worker } else {
256*d9f75844SAndroid Build Coastguard Worker auto old_transport = it->second;
257*d9f75844SAndroid Build Coastguard Worker it->second = jsep_transport;
258*d9f75844SAndroid Build Coastguard Worker MaybeDestroyJsepTransport(old_transport);
259*d9f75844SAndroid Build Coastguard Worker }
260*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
261*d9f75844SAndroid Build Coastguard Worker return result;
262*d9f75844SAndroid Build Coastguard Worker }
263*d9f75844SAndroid Build Coastguard Worker
RemoveTransportForMid(const std::string & mid)264*d9f75844SAndroid Build Coastguard Worker void JsepTransportCollection::RemoveTransportForMid(const std::string& mid) {
265*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
266*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
267*d9f75844SAndroid Build Coastguard Worker bool ret = map_change_callback_(mid, nullptr);
268*d9f75844SAndroid Build Coastguard Worker // Calling OnTransportChanged with nullptr should always succeed, since it is
269*d9f75844SAndroid Build Coastguard Worker // only expected to fail when adding media to a transport (not removing).
270*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(ret);
271*d9f75844SAndroid Build Coastguard Worker
272*d9f75844SAndroid Build Coastguard Worker auto old_transport = GetTransportForMid(mid);
273*d9f75844SAndroid Build Coastguard Worker if (old_transport) {
274*d9f75844SAndroid Build Coastguard Worker mid_to_transport_.erase(mid);
275*d9f75844SAndroid Build Coastguard Worker MaybeDestroyJsepTransport(old_transport);
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
278*d9f75844SAndroid Build Coastguard Worker }
279*d9f75844SAndroid Build Coastguard Worker
RollbackTransports()280*d9f75844SAndroid Build Coastguard Worker bool JsepTransportCollection::RollbackTransports() {
281*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
282*d9f75844SAndroid Build Coastguard Worker bool ret = true;
283*d9f75844SAndroid Build Coastguard Worker // First, remove any new mid->transport mappings.
284*d9f75844SAndroid Build Coastguard Worker for (const auto& kv : mid_to_transport_) {
285*d9f75844SAndroid Build Coastguard Worker if (stable_mid_to_transport_.count(kv.first) == 0) {
286*d9f75844SAndroid Build Coastguard Worker ret = ret && map_change_callback_(kv.first, nullptr);
287*d9f75844SAndroid Build Coastguard Worker }
288*d9f75844SAndroid Build Coastguard Worker }
289*d9f75844SAndroid Build Coastguard Worker // Next, restore old mappings.
290*d9f75844SAndroid Build Coastguard Worker for (const auto& kv : stable_mid_to_transport_) {
291*d9f75844SAndroid Build Coastguard Worker auto it = mid_to_transport_.find(kv.first);
292*d9f75844SAndroid Build Coastguard Worker if (it == mid_to_transport_.end() || it->second != kv.second) {
293*d9f75844SAndroid Build Coastguard Worker ret = ret && map_change_callback_(kv.first, kv.second);
294*d9f75844SAndroid Build Coastguard Worker }
295*d9f75844SAndroid Build Coastguard Worker }
296*d9f75844SAndroid Build Coastguard Worker mid_to_transport_ = stable_mid_to_transport_;
297*d9f75844SAndroid Build Coastguard Worker // Moving a transport back to mid_to_transport_ means it's now included in
298*d9f75844SAndroid Build Coastguard Worker // the aggregate state if it wasn't previously.
299*d9f75844SAndroid Build Coastguard Worker state_change_callback_();
300*d9f75844SAndroid Build Coastguard Worker DestroyUnusedTransports();
301*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
302*d9f75844SAndroid Build Coastguard Worker return ret;
303*d9f75844SAndroid Build Coastguard Worker }
304*d9f75844SAndroid Build Coastguard Worker
CommitTransports()305*d9f75844SAndroid Build Coastguard Worker void JsepTransportCollection::CommitTransports() {
306*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
307*d9f75844SAndroid Build Coastguard Worker stable_mid_to_transport_ = mid_to_transport_;
308*d9f75844SAndroid Build Coastguard Worker DestroyUnusedTransports();
309*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
310*d9f75844SAndroid Build Coastguard Worker }
311*d9f75844SAndroid Build Coastguard Worker
TransportInUse(cricket::JsepTransport * jsep_transport) const312*d9f75844SAndroid Build Coastguard Worker bool JsepTransportCollection::TransportInUse(
313*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* jsep_transport) const {
314*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
315*d9f75844SAndroid Build Coastguard Worker for (const auto& kv : mid_to_transport_) {
316*d9f75844SAndroid Build Coastguard Worker if (kv.second == jsep_transport) {
317*d9f75844SAndroid Build Coastguard Worker return true;
318*d9f75844SAndroid Build Coastguard Worker }
319*d9f75844SAndroid Build Coastguard Worker }
320*d9f75844SAndroid Build Coastguard Worker return false;
321*d9f75844SAndroid Build Coastguard Worker }
322*d9f75844SAndroid Build Coastguard Worker
TransportNeededForRollback(cricket::JsepTransport * jsep_transport) const323*d9f75844SAndroid Build Coastguard Worker bool JsepTransportCollection::TransportNeededForRollback(
324*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* jsep_transport) const {
325*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
326*d9f75844SAndroid Build Coastguard Worker for (const auto& kv : stable_mid_to_transport_) {
327*d9f75844SAndroid Build Coastguard Worker if (kv.second == jsep_transport) {
328*d9f75844SAndroid Build Coastguard Worker return true;
329*d9f75844SAndroid Build Coastguard Worker }
330*d9f75844SAndroid Build Coastguard Worker }
331*d9f75844SAndroid Build Coastguard Worker return false;
332*d9f75844SAndroid Build Coastguard Worker }
333*d9f75844SAndroid Build Coastguard Worker
MaybeDestroyJsepTransport(cricket::JsepTransport * transport)334*d9f75844SAndroid Build Coastguard Worker void JsepTransportCollection::MaybeDestroyJsepTransport(
335*d9f75844SAndroid Build Coastguard Worker cricket::JsepTransport* transport) {
336*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
337*d9f75844SAndroid Build Coastguard Worker // Don't destroy the JsepTransport if there are still media sections referring
338*d9f75844SAndroid Build Coastguard Worker // to it, or if it will be needed in case of rollback.
339*d9f75844SAndroid Build Coastguard Worker if (TransportInUse(transport)) {
340*d9f75844SAndroid Build Coastguard Worker return;
341*d9f75844SAndroid Build Coastguard Worker }
342*d9f75844SAndroid Build Coastguard Worker // If this transport is needed for rollback, don't destroy it yet, but make
343*d9f75844SAndroid Build Coastguard Worker // sure the aggregate state is updated since this transport is no longer
344*d9f75844SAndroid Build Coastguard Worker // included in it.
345*d9f75844SAndroid Build Coastguard Worker if (TransportNeededForRollback(transport)) {
346*d9f75844SAndroid Build Coastguard Worker state_change_callback_();
347*d9f75844SAndroid Build Coastguard Worker return;
348*d9f75844SAndroid Build Coastguard Worker }
349*d9f75844SAndroid Build Coastguard Worker for (const auto& it : jsep_transports_by_name_) {
350*d9f75844SAndroid Build Coastguard Worker if (it.second.get() == transport) {
351*d9f75844SAndroid Build Coastguard Worker jsep_transports_by_name_.erase(it.first);
352*d9f75844SAndroid Build Coastguard Worker state_change_callback_();
353*d9f75844SAndroid Build Coastguard Worker break;
354*d9f75844SAndroid Build Coastguard Worker }
355*d9f75844SAndroid Build Coastguard Worker }
356*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(IsConsistent());
357*d9f75844SAndroid Build Coastguard Worker }
358*d9f75844SAndroid Build Coastguard Worker
DestroyUnusedTransports()359*d9f75844SAndroid Build Coastguard Worker void JsepTransportCollection::DestroyUnusedTransports() {
360*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
361*d9f75844SAndroid Build Coastguard Worker bool need_state_change_callback = false;
362*d9f75844SAndroid Build Coastguard Worker auto it = jsep_transports_by_name_.begin();
363*d9f75844SAndroid Build Coastguard Worker while (it != jsep_transports_by_name_.end()) {
364*d9f75844SAndroid Build Coastguard Worker if (TransportInUse(it->second.get()) ||
365*d9f75844SAndroid Build Coastguard Worker TransportNeededForRollback(it->second.get())) {
366*d9f75844SAndroid Build Coastguard Worker ++it;
367*d9f75844SAndroid Build Coastguard Worker } else {
368*d9f75844SAndroid Build Coastguard Worker it = jsep_transports_by_name_.erase(it);
369*d9f75844SAndroid Build Coastguard Worker need_state_change_callback = true;
370*d9f75844SAndroid Build Coastguard Worker }
371*d9f75844SAndroid Build Coastguard Worker }
372*d9f75844SAndroid Build Coastguard Worker if (need_state_change_callback) {
373*d9f75844SAndroid Build Coastguard Worker state_change_callback_();
374*d9f75844SAndroid Build Coastguard Worker }
375*d9f75844SAndroid Build Coastguard Worker }
376*d9f75844SAndroid Build Coastguard Worker
IsConsistent()377*d9f75844SAndroid Build Coastguard Worker bool JsepTransportCollection::IsConsistent() {
378*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&sequence_checker_);
379*d9f75844SAndroid Build Coastguard Worker for (const auto& it : jsep_transports_by_name_) {
380*d9f75844SAndroid Build Coastguard Worker if (!TransportInUse(it.second.get()) &&
381*d9f75844SAndroid Build Coastguard Worker !TransportNeededForRollback(it.second.get())) {
382*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Transport registered with mid " << it.first
383*d9f75844SAndroid Build Coastguard Worker << " is not in use, transport " << it.second.get();
384*d9f75844SAndroid Build Coastguard Worker return false;
385*d9f75844SAndroid Build Coastguard Worker }
386*d9f75844SAndroid Build Coastguard Worker }
387*d9f75844SAndroid Build Coastguard Worker return true;
388*d9f75844SAndroid Build Coastguard Worker }
389*d9f75844SAndroid Build Coastguard Worker
390*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
391