void BundleManager::Update(const SessionDescription* description,
SdpType type) {
RTC_DCHECK_RUN_ON(&sequence_checker_); // Rollbacks should call Rollback, not Update.
RTC_DCHECK(type != SdpType::kRollback); bool bundle_groups_changed = false; // TODO: bugs.webrtc.org/42228228 - Evaluate whether a PR-Answer can establish // a bundle and a final Answer can remove it again. If this happens, PRAnswer // should not destroy the unused transport.
if (bundle_policy_ == PeerConnectionInterface::kBundlePolicyMaxBundle ||
type == SdpType::kAnswer || type == SdpType::kPrAnswer) { // If our policy is "max-bundle" or this is an answer, update all bundle // groups.
bundle_groups_changed = true;
bundle_groups_.clear();
for (const ContentGroup* new_bundle_group :
description->GetGroupsByName(GROUP_TYPE_BUNDLE)) {
bundle_groups_.push_back(
std::make_unique<ContentGroup>(*new_bundle_group));
RTC_DLOG(LS_VERBOSE) << "Establishing bundle group "
<< new_bundle_group->ToString();
}
} else if (type == SdpType::kOffer) { // If this is an offer, update existing bundle groups. // We do this because as per RFC 8843, section 7.3.2, the answerer cannot // remove an m= section from an existing BUNDLE group without rejecting it. // Thus any m= sections added to a BUNDLE group in this offer can // preemptively start using the bundled transport, as there is no possible // non-bundled fallback.
for (const ContentGroup* new_bundle_group :
description->GetGroupsByName(GROUP_TYPE_BUNDLE)) { // Attempt to find a matching existing group.
for (const std::string& mid : new_bundle_group->content_names()) { auto it = established_bundle_groups_by_mid_.find(mid);
if (it != established_bundle_groups_by_mid_.end()) {
*it->second = *new_bundle_group;
bundle_groups_changed = true;
RTC_DLOG(LS_VERBOSE)
<< "Establishing bundle group " << new_bundle_group->ToString(); break;
}
}
}
}
if (bundle_groups_changed) {
RefreshEstablishedBundleGroupsByMid();
}
}
const ContentGroup* BundleManager::LookupGroupByMid(
absl::string_view mid) const { auto it = established_bundle_groups_by_mid_.find(mid); return it != established_bundle_groups_by_mid_.end() ? it->second : nullptr;
} bool BundleManager::IsFirstMidInGroup(absl::string_view mid) const { auto group = LookupGroupByMid(mid);
if (!group) { returntrue; // Unbundled MIDs are considered group leaders
} return mid == *(group->FirstContentName());
}
ContentGroup* BundleManager::LookupGroupByMid(absl::string_view mid) { auto it = established_bundle_groups_by_mid_.find(mid); return it != established_bundle_groups_by_mid_.end() ? it->second : nullptr;
}
void BundleManager::DeleteMid(const ContentGroup* bundle_group,
absl::string_view mid) {
RTC_DCHECK_RUN_ON(&sequence_checker_);
RTC_LOG(LS_VERBOSE) << "Deleting mid " << mid << " from bundle group "
<< bundle_group->ToString(); // Remove the rejected content from the `bundle_group`. // The const pointer arg is used to identify the group, we verify // it before we use it to make a modification. auto bundle_group_it =
std::find_if(bundle_groups_.begin(), bundle_groups_.end(),
[bundle_group](std::unique_ptr<ContentGroup>& group) { return bundle_group == group.get();
});
RTC_DCHECK(bundle_group_it != bundle_groups_.end());
(*bundle_group_it)->RemoveContentName(mid);
established_bundle_groups_by_mid_.erase(
established_bundle_groups_by_mid_.find(mid));
}
auto it = mid_to_transport_.find(mid);
if (it != mid_to_transport_.end() && it->second == jsep_transport) returntrue;
// The map_change_callback must be called before destroying the // transport, because it removes references to the transport // in the RTP demuxer. bool result = map_change_callback_(mid, jsep_transport);
void JsepTransportCollection::RemoveTransportForMid(absl::string_view mid) {
RTC_DCHECK_RUN_ON(&sequence_checker_);
RTC_DCHECK(IsConsistent()); bool ret = map_change_callback_(mid, nullptr); // Calling OnTransportChanged with nullptr should always succeed, since it is // only expected to fail when adding media to a transport (not removing).
RTC_DCHECK(ret);
auto old_transport = GetTransportForMid(mid);
if (old_transport) {
mid_to_transport_.erase(mid);
MaybeDestroyJsepTransport(old_transport);
}
RTC_DCHECK(IsConsistent());
}
bool JsepTransportCollection::RollbackTransports() {
RTC_DCHECK_RUN_ON(&sequence_checker_); bool ret = true; // First, remove any new mid->transport mappings.
for (constauto& kv : mid_to_transport_) {
if (stable_mid_to_transport_.count(kv.first) == 0) { bool success = map_change_callback_(kv.first, nullptr);
ret = ret && success;
}
} // Next, restore old mappings.
for (constauto& kv : stable_mid_to_transport_) { auto it = mid_to_transport_.find(kv.first);
if (it == mid_to_transport_.end() || it->second != kv.second) { bool success = map_change_callback_(kv.first, kv.second);
ret = ret && success;
}
}
mid_to_transport_ = stable_mid_to_transport_; // Moving a transport back to mid_to_transport_ means it's now included in // the aggregate state if it wasn't previously.
state_change_callback_();
DestroyUnusedTransports();
RTC_DCHECK(IsConsistent()); return ret;
}
void JsepTransportCollection::MaybeDestroyJsepTransport(
JsepTransport* transport) {
RTC_DCHECK_RUN_ON(&sequence_checker_); // Don't destroy the JsepTransport if there are still media sections // referring to it, or if it will be needed in case of rollback.
if (TransportInUse(transport)) { return;
} // If this transport is needed for rollback, don't destroy it yet, but make // sure the aggregate state is updated since this transport is no longer // included in it.
if (TransportNeededForRollback(transport)) {
state_change_callback_(); return;
} auto it = absl::c_find_if(
transports_, [&](constauto& t) { return t.get() == transport; });
if (it != transports_.end()) {
transports_.erase(it);
state_change_callback_();
}
RTC_DCHECK(IsConsistent());
}
void JsepTransportCollection::DestroyUnusedTransports() {
RTC_DCHECK_RUN_ON(&sequence_checker_); bool need_state_change_callback = false; auto it = transports_.begin(); while (it != transports_.end()) {
if (TransportInUse(it->get()) || TransportNeededForRollback(it->get())) {
++it;
} else {
it = transports_.erase(it);
need_state_change_callback = true;
}
}
if (need_state_change_callback) {
state_change_callback_();
}
}
bool JsepTransportCollection::IsConsistent() {
RTC_DCHECK_RUN_ON(&sequence_checker_); bool consistent = true;
for (constauto& t : transports_) {
if (!TransportInUse(t.get()) && !TransportNeededForRollback(t.get())) {
RTC_LOG(LS_ERROR) << "Transport registered with mid " << t->name()
<< " is not in use";
consistent = false;
}
} return consistent;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.