// Update the connection address for the MediaContentDescription based on the // candidates. void UpdateConnectionAddress(const IceCandidateCollection& candidate_collection,
MediaContentDescription* media_desc) {
int port = kDummyPort;
std::string ip = kDummyAddress;
std::string hostname;
int current_preference = 0; // Start with lowest preference.
int current_family = AF_UNSPEC;
for (size_t i = 0; i < candidate_collection.count(); ++i) { const IceCandidate* jsep_candidate = candidate_collection.at(i);
if (jsep_candidate->candidate().component() !=
ICE_CANDIDATE_COMPONENT_RTP) { continue;
} // Default destination should be UDP only.
if (jsep_candidate->candidate().protocol() != UDP_PROTOCOL_NAME) { continue;
} const int preference = jsep_candidate->candidate().type_preference(); const int family = jsep_candidate->candidate().address().ipaddr().family(); // See if this candidate is more preferable then the current one if it's the // same family. Or if the current family is IPv4 already so we could safely // ignore all IPv6 ones. WebRTC bug 4269. // http://code.google.com/p/webrtc/issues/detail?id=4269
if ((preference <= current_preference && current_family == family) ||
(current_family == AF_INET && family == AF_INET6)) { continue;
}
current_preference = preference;
current_family = family; const SocketAddress& candidate_addr = jsep_candidate->candidate().address();
port = candidate_addr.port();
ip = candidate_addr.ipaddr().ToString();
hostname = candidate_addr.hostname();
}
SocketAddress connection_addr(ip, port);
if (IPIsUnspec(connection_addr.ipaddr()) && !hostname.empty()) { // When a hostname candidate becomes the (default) connection address, // we use the dummy address 0.0.0.0 and port 9 in the c= and the m= lines. // // We have observed in deployment that with a FQDN in a c= line, SDP parsing // could fail in other JSEP implementations. We note that the wildcard // addresses (0.0.0.0 or ::) with port 9 are given the exception as the // connection address that will not result in an ICE mismatch // (draft-ietf-mmusic-ice-sip-sdp). Also, 0.0.0.0 or :: can be used as the // connection address in the initial offer or answer with trickle ICE // if the offerer or answerer does not want to include the host IP address // (draft-ietf-mmusic-trickle-ice-sip), and in particular 0.0.0.0 has been // widely deployed for this use without outstanding compatibility issues. // Combining the above considerations, we use 0.0.0.0 with port 9 to // populate the c= and the m= lines. See `BuildMediaDescription` in // webrtc_sdp.cc for the SDP generation with // `media_desc->connection_address()`.
connection_addr = SocketAddress(kDummyAddress, kDummyPort);
}
media_desc->set_connection_address(connection_addr);
}
void SessionDescriptionInterface::RelinquishThreadOwnership() { // Ideally we should require that the method can only be called from the // thread that the sequence checker is currently attached to. However that's // not compatible with some cases outside of webrtc where initializations // happens on one thread and then the object is moved to a second thread (e.g. // signaling) where a call is made into webrtc. At that point we'd hit a // dcheck like this in webrtc: RTC_DCHECK_RUN_ON(&sequence_checker_);
sequence_checker_.Detach(); // Tie the checker to the current thread, which permits iterating // `candidate_collection_`
RTC_DCHECK_RUN_ON(&sequence_checker_);
for (IceCandidateCollection& collection : candidate_collection_) {
collection.RelinquishThreadOwnership();
}
sequence_checker_.Detach(); // Unties the checker from the current thread.
}
bool SessionDescriptionInterface::AddCandidate(const IceCandidate* candidate) {
RTC_DCHECK_RUN_ON(&sequence_checker_);
if (!candidate) return false;
size_t index = 0;
if (!GetMediasectionIndex(candidate, &index)) { return false;
}
ContentInfo& content = description()->contents()[index]; const TransportInfo* transport_info =
description()->GetTransportInfoByName(content.mid());
if (!transport_info) { return false;
}
Candidate updated_candidate = candidate->candidate();
if (updated_candidate.username().empty()) {
updated_candidate.set_username(transport_info->description.ice_ufrag);
}
if (updated_candidate.password().empty()) {
updated_candidate.set_password(transport_info->description.ice_pwd);
}
// Use `content.mid()` as the mid for the updated candidate. The // `candidate->sdp_mid()` property *should* be the same. However, in some // cases specifying an empty mid but a valid index is a way to add a candidate // without knowing (or caring about) the mid. This is done in several tests.
RTC_DCHECK(candidate->sdp_mid().empty() ||
candidate->sdp_mid() == content.mid())
<< "sdp_mid='" << candidate->sdp_mid() << "' content.mid()='"
<< content.mid() << "'"; auto updated_candidate_wrapper = std::make_unique<IceCandidate>(
content.mid(), static_cast<int>(index), updated_candidate);
IceCandidateCollection& candidates = candidate_collection_[index];
if (!candidates.HasCandidate(updated_candidate_wrapper.get())) {
candidates.add(std::move(updated_candidate_wrapper));
UpdateConnectionAddress(candidates, content.media_description());
}
auto mid = candidate->sdp_mid();
if (!mid.empty()) {
*index = GetMediasectionIndex(mid);
} else { // An sdp_mline_index of -1 will be treated as invalid.
*index = static_cast<size_t>(candidate->sdp_mline_index());
} return IsValidMLineIndex(*index);
}
int SessionDescriptionInterface::GetMediasectionIndex(
absl::string_view mid) const { constauto& contents = description()->contents(); auto it =
std::find_if(contents.begin(), contents.end(),
[&](constauto& content) { return mid == content.mid(); }); return it == contents.end() ? -1 : std::distance(contents.begin(), it);
}
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.