/* * Copyright 2018 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 "api/jsep_ice_candidate.h" #include #include #include #include #include #include #include #include "absl/algorithm/container.h" #include "absl/base/nullability.h" #include "absl/memory/memory.h" #include "absl/strings/string_view.h" #include "api/candidate.h" #include "api/jsep.h" #include "api/rtc_error.h" #include "api/sequence_checker.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" namespace webrtc { namespace { // The sdpMLineIndex property is an unsigned short, a zero based index of the // m-line associated with the candidate. This function ensures we consistently // set the property to -1 for out-of-bounds values, to make candidate // comparisons more robust. int EnsureValidMLineIndex(int sdp_mline_index) { if (sdp_mline_index < 0 || sdp_mline_index > std::numeric_limits::max()) return -1; return sdp_mline_index; } } // namespace // static std::unique_ptr IceCandidate::Create(absl::string_view mid, int sdp_mline_index, absl::string_view sdp, SdpParseError* absl_nullable error /*= nullptr*/) { RTCErrorOr c = Candidate::ParseCandidateString(sdp); if (!c.ok()) { if (error) { error->line = sdp; error->description = c.error().message(); } return nullptr; } return std::make_unique(mid, sdp_mline_index, c.value()); } IceCandidate::IceCandidate(absl::string_view sdp_mid, int sdp_mline_index, const Candidate& candidate) : sdp_mid_(sdp_mid), sdp_mline_index_(EnsureValidMLineIndex(sdp_mline_index)), candidate_(candidate) { if (sdp_mid_.empty() && sdp_mline_index_ < 0) { RTC_LOG(LS_ERROR) << "Neither mid nor index supplied for IceCandidate."; } } void IceCandidateCollection::add(std::unique_ptr candidate) { RTC_DCHECK_RUN_ON(&sequence_checker_); candidates_.push_back(std::move(candidate)); } void IceCandidateCollection::add(IceCandidate* candidate) { RTC_DCHECK_RUN_ON(&sequence_checker_); candidates_.push_back(absl::WrapUnique(candidate)); } void IceCandidateCollection::Append(IceCandidateCollection collection) { RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_RUN_ON(&collection.sequence_checker_); candidates_.insert(candidates_.end(), std::make_move_iterator(collection.candidates_.begin()), std::make_move_iterator(collection.candidates_.end())); } const IceCandidate* IceCandidateCollection::at(size_t index) const { RTC_DCHECK_RUN_ON(&sequence_checker_); return candidates_[index].get(); } bool IceCandidateCollection::HasCandidate(const IceCandidate* candidate) const { RTC_DCHECK_RUN_ON(&sequence_checker_); const auto sdp_mid = candidate->sdp_mid(); // avoid string copy per entry. return absl::c_any_of( candidates_, [&](const std::unique_ptr& entry) { if (!entry->candidate().IsEquivalent(candidate->candidate())) { return false; } if (!sdp_mid.empty()) { // In this case, we ignore the `sdp_mline_index()` property. return sdp_mid == entry->sdp_mid(); } RTC_DCHECK_NE(candidate->sdp_mline_index(), -1); return candidate->sdp_mline_index() == entry->sdp_mline_index(); }); } IceCandidateCollection IceCandidateCollection::Clone() const { IceCandidateCollection new_collection; RTC_DCHECK_RUN_ON(&sequence_checker_); RTC_DCHECK_RUN_ON(&new_collection.sequence_checker_); new_collection.candidates_.reserve(candidates_.size()); for (const auto& candidate : candidates_) { new_collection.candidates_.push_back(std::make_unique( candidate->sdp_mid(), candidate->sdp_mline_index(), candidate->candidate())); } return new_collection; } size_t IceCandidateCollection::remove(const IceCandidate* candidate) { RTC_DCHECK(candidate); RTC_DCHECK_RUN_ON(&sequence_checker_); auto iter = absl::c_find_if(candidates_, [&](const std::unique_ptr& c) { return c->candidate().MatchesForRemoval(candidate->candidate()); }); if (iter != candidates_.end()) { candidates_.erase(iter); return 1u; } return 0u; } void IceCandidateCollection::RelinquishThreadOwnership() { sequence_checker_.Detach(); } std::string IceCandidate::ToString() const { return candidate_.ToCandidateAttribute(true); } } // namespace webrtc