|  | /* | 
|  | *  Copyright 2010 The WebRTC Project Authors. All rights reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "pc/session_description.h" | 
|  |  | 
|  | #include "absl/algorithm/container.h" | 
|  | #include "absl/memory/memory.h" | 
|  | #include "rtc_base/checks.h" | 
|  | #include "rtc_base/strings/string_builder.h" | 
|  |  | 
|  | namespace cricket { | 
|  | namespace { | 
|  |  | 
|  | ContentInfo* FindContentInfoByName(ContentInfos* contents, | 
|  | const std::string& name) { | 
|  | RTC_DCHECK(contents); | 
|  | for (ContentInfo& content : *contents) { | 
|  | if (content.name == name) { | 
|  | return &content; | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | const ContentInfo* FindContentInfoByName(const ContentInfos& contents, | 
|  | const std::string& name) { | 
|  | for (ContentInfos::const_iterator content = contents.begin(); | 
|  | content != contents.end(); ++content) { | 
|  | if (content->name == name) { | 
|  | return &(*content); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | const ContentInfo* FindContentInfoByType(const ContentInfos& contents, | 
|  | MediaProtocolType type) { | 
|  | for (const auto& content : contents) { | 
|  | if (content.type == type) { | 
|  | return &content; | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ContentGroup::ContentGroup(const std::string& semantics) | 
|  | : semantics_(semantics) {} | 
|  |  | 
|  | ContentGroup::ContentGroup(const ContentGroup&) = default; | 
|  | ContentGroup::ContentGroup(ContentGroup&&) = default; | 
|  | ContentGroup& ContentGroup::operator=(const ContentGroup&) = default; | 
|  | ContentGroup& ContentGroup::operator=(ContentGroup&&) = default; | 
|  | ContentGroup::~ContentGroup() = default; | 
|  |  | 
|  | const std::string* ContentGroup::FirstContentName() const { | 
|  | return (!content_names_.empty()) ? &(*content_names_.begin()) : NULL; | 
|  | } | 
|  |  | 
|  | bool ContentGroup::HasContentName(absl::string_view content_name) const { | 
|  | return absl::c_linear_search(content_names_, content_name); | 
|  | } | 
|  |  | 
|  | void ContentGroup::AddContentName(absl::string_view content_name) { | 
|  | if (!HasContentName(content_name)) { | 
|  | content_names_.emplace_back(content_name); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool ContentGroup::RemoveContentName(absl::string_view content_name) { | 
|  | ContentNames::iterator iter = absl::c_find(content_names_, content_name); | 
|  | if (iter == content_names_.end()) { | 
|  | return false; | 
|  | } | 
|  | content_names_.erase(iter); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::string ContentGroup::ToString() const { | 
|  | rtc::StringBuilder acc; | 
|  | acc << semantics_ << "("; | 
|  | if (!content_names_.empty()) { | 
|  | for (const auto& name : content_names_) { | 
|  | acc << name << " "; | 
|  | } | 
|  | } | 
|  | acc << ")"; | 
|  | return acc.Release(); | 
|  | } | 
|  |  | 
|  | SessionDescription::SessionDescription() = default; | 
|  | SessionDescription::SessionDescription(const SessionDescription&) = default; | 
|  |  | 
|  | SessionDescription::~SessionDescription() {} | 
|  |  | 
|  | std::unique_ptr<SessionDescription> SessionDescription::Clone() const { | 
|  | // Copy using the private copy constructor. | 
|  | // This will clone the descriptions using ContentInfo's copy constructor. | 
|  | return absl::WrapUnique(new SessionDescription(*this)); | 
|  | } | 
|  |  | 
|  | const ContentInfo* SessionDescription::GetContentByName( | 
|  | const std::string& name) const { | 
|  | return FindContentInfoByName(contents_, name); | 
|  | } | 
|  |  | 
|  | ContentInfo* SessionDescription::GetContentByName(const std::string& name) { | 
|  | return FindContentInfoByName(&contents_, name); | 
|  | } | 
|  |  | 
|  | const MediaContentDescription* SessionDescription::GetContentDescriptionByName( | 
|  | const std::string& name) const { | 
|  | const ContentInfo* cinfo = FindContentInfoByName(contents_, name); | 
|  | if (cinfo == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return cinfo->media_description(); | 
|  | } | 
|  |  | 
|  | MediaContentDescription* SessionDescription::GetContentDescriptionByName( | 
|  | const std::string& name) { | 
|  | ContentInfo* cinfo = FindContentInfoByName(&contents_, name); | 
|  | if (cinfo == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return cinfo->media_description(); | 
|  | } | 
|  |  | 
|  | const ContentInfo* SessionDescription::FirstContentByType( | 
|  | MediaProtocolType type) const { | 
|  | return FindContentInfoByType(contents_, type); | 
|  | } | 
|  |  | 
|  | const ContentInfo* SessionDescription::FirstContent() const { | 
|  | return (contents_.empty()) ? NULL : &(*contents_.begin()); | 
|  | } | 
|  |  | 
|  | void SessionDescription::AddContent( | 
|  | const std::string& name, | 
|  | MediaProtocolType type, | 
|  | std::unique_ptr<MediaContentDescription> description) { | 
|  | ContentInfo content(type); | 
|  | content.name = name; | 
|  | content.set_media_description(std::move(description)); | 
|  | AddContent(std::move(content)); | 
|  | } | 
|  |  | 
|  | void SessionDescription::AddContent( | 
|  | const std::string& name, | 
|  | MediaProtocolType type, | 
|  | bool rejected, | 
|  | std::unique_ptr<MediaContentDescription> description) { | 
|  | ContentInfo content(type); | 
|  | content.name = name; | 
|  | content.rejected = rejected; | 
|  | content.set_media_description(std::move(description)); | 
|  | AddContent(std::move(content)); | 
|  | } | 
|  |  | 
|  | void SessionDescription::AddContent( | 
|  | const std::string& name, | 
|  | MediaProtocolType type, | 
|  | bool rejected, | 
|  | bool bundle_only, | 
|  | std::unique_ptr<MediaContentDescription> description) { | 
|  | ContentInfo content(type); | 
|  | content.name = name; | 
|  | content.rejected = rejected; | 
|  | content.bundle_only = bundle_only; | 
|  | content.set_media_description(std::move(description)); | 
|  | AddContent(std::move(content)); | 
|  | } | 
|  |  | 
|  | void SessionDescription::AddContent(ContentInfo&& content) { | 
|  | if (extmap_allow_mixed()) { | 
|  | // Mixed support on session level overrides setting on media level. | 
|  | content.media_description()->set_extmap_allow_mixed_enum( | 
|  | MediaContentDescription::kSession); | 
|  | } | 
|  | contents_.push_back(std::move(content)); | 
|  | } | 
|  |  | 
|  | bool SessionDescription::RemoveContentByName(const std::string& name) { | 
|  | for (ContentInfos::iterator content = contents_.begin(); | 
|  | content != contents_.end(); ++content) { | 
|  | if (content->name == name) { | 
|  | contents_.erase(content); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void SessionDescription::AddTransportInfo(const TransportInfo& transport_info) { | 
|  | transport_infos_.push_back(transport_info); | 
|  | } | 
|  |  | 
|  | bool SessionDescription::RemoveTransportInfoByName(const std::string& name) { | 
|  | for (TransportInfos::iterator transport_info = transport_infos_.begin(); | 
|  | transport_info != transport_infos_.end(); ++transport_info) { | 
|  | if (transport_info->content_name == name) { | 
|  | transport_infos_.erase(transport_info); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const TransportInfo* SessionDescription::GetTransportInfoByName( | 
|  | const std::string& name) const { | 
|  | for (TransportInfos::const_iterator iter = transport_infos_.begin(); | 
|  | iter != transport_infos_.end(); ++iter) { | 
|  | if (iter->content_name == name) { | 
|  | return &(*iter); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | TransportInfo* SessionDescription::GetTransportInfoByName( | 
|  | const std::string& name) { | 
|  | for (TransportInfos::iterator iter = transport_infos_.begin(); | 
|  | iter != transport_infos_.end(); ++iter) { | 
|  | if (iter->content_name == name) { | 
|  | return &(*iter); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | void SessionDescription::RemoveGroupByName(const std::string& name) { | 
|  | for (ContentGroups::iterator iter = content_groups_.begin(); | 
|  | iter != content_groups_.end(); ++iter) { | 
|  | if (iter->semantics() == name) { | 
|  | content_groups_.erase(iter); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SessionDescription::HasGroup(const std::string& name) const { | 
|  | for (ContentGroups::const_iterator iter = content_groups_.begin(); | 
|  | iter != content_groups_.end(); ++iter) { | 
|  | if (iter->semantics() == name) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const ContentGroup* SessionDescription::GetGroupByName( | 
|  | const std::string& name) const { | 
|  | for (ContentGroups::const_iterator iter = content_groups_.begin(); | 
|  | iter != content_groups_.end(); ++iter) { | 
|  | if (iter->semantics() == name) { | 
|  | return &(*iter); | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | std::vector<const ContentGroup*> SessionDescription::GetGroupsByName( | 
|  | const std::string& name) const { | 
|  | std::vector<const ContentGroup*> content_groups; | 
|  | for (const ContentGroup& content_group : content_groups_) { | 
|  | if (content_group.semantics() == name) { | 
|  | content_groups.push_back(&content_group); | 
|  | } | 
|  | } | 
|  | return content_groups; | 
|  | } | 
|  |  | 
|  | ContentInfo::~ContentInfo() { | 
|  | } | 
|  |  | 
|  | // Copy operator. | 
|  | ContentInfo::ContentInfo(const ContentInfo& o) | 
|  | : name(o.name), | 
|  | type(o.type), | 
|  | rejected(o.rejected), | 
|  | bundle_only(o.bundle_only), | 
|  | description_(o.description_->Clone()) {} | 
|  |  | 
|  | ContentInfo& ContentInfo::operator=(const ContentInfo& o) { | 
|  | name = o.name; | 
|  | type = o.type; | 
|  | rejected = o.rejected; | 
|  | bundle_only = o.bundle_only; | 
|  | description_ = o.description_->Clone(); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | const MediaContentDescription* ContentInfo::media_description() const { | 
|  | return description_.get(); | 
|  | } | 
|  |  | 
|  | MediaContentDescription* ContentInfo::media_description() { | 
|  | return description_.get(); | 
|  | } | 
|  |  | 
|  | }  // namespace cricket |