blob: 7f0bb03232477d054dffed0d98ed7f27dda30835 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_adapter_impl.h"
#include <utility>
#include "base/notreached.h"
#include "third_party/webrtc/api/ice_transport_factory.h"
namespace blink {
IceTransportAdapterImpl::IceTransportAdapterImpl(
Delegate* delegate,
std::unique_ptr<cricket::PortAllocator> port_allocator,
std::unique_ptr<webrtc::AsyncResolverFactory> async_resolver_factory)
: delegate_(delegate),
port_allocator_(std::move(port_allocator)),
async_resolver_factory_(std::move(async_resolver_factory)) {
// These settings are copied from PeerConnection:
// https://codesearch.chromium.org/chromium/src/third_party/webrtc/pc/peerconnection.cc?l=4708&rcl=820ebd0f661696043959b5105b2814e0edd8b694
port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
port_allocator_->set_flags(port_allocator_->flags() |
cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
cricket::PORTALLOCATOR_ENABLE_IPV6 |
cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
port_allocator_->Initialize();
webrtc::IceTransportInit ice_transport_init;
ice_transport_init.set_port_allocator(port_allocator_.get());
ice_transport_init.set_async_resolver_factory(async_resolver_factory_.get());
ice_transport_channel_ =
webrtc::CreateIceTransport(std::move(ice_transport_init));
SetupIceTransportChannel();
// We need to set the ICE role even before Start is called since the Port
// assumes that the role has been set before receiving incoming connectivity
// checks. These checks can race with the information signaled for Start.
ice_transport_channel()->SetIceRole(cricket::ICEROLE_CONTROLLING);
// The ICE tiebreaker is used to determine which side is controlling/
// controlled when both sides start in the same role. The number is randomly
// generated so that each peer can calculate a.tiebreaker <= b.tiebreaker
// consistently.
ice_transport_channel()->SetIceTiebreaker(rtc::CreateRandomId64());
}
IceTransportAdapterImpl::IceTransportAdapterImpl(
Delegate* delegate,
rtc::scoped_refptr<webrtc::IceTransportInterface> ice_transport)
: delegate_(delegate), ice_transport_channel_(ice_transport) {
// The native webrtc peer connection might have been closed in the meantime,
// clearing the ice transport channel; don't do anything in that case. |this|
// will eventually be destroyed when the blink layer gets notified by the
// webrtc layer that the transport has been cleared.
if (ice_transport_channel())
SetupIceTransportChannel();
}
IceTransportAdapterImpl::~IceTransportAdapterImpl() = default;
static uint32_t GetCandidateFilterForPolicy(IceTransportPolicy policy) {
switch (policy) {
case IceTransportPolicy::kRelay:
return cricket::CF_RELAY;
case IceTransportPolicy::kAll:
return cricket::CF_ALL;
}
NOTREACHED();
return 0;
}
void IceTransportAdapterImpl::StartGathering(
const cricket::IceParameters& local_parameters,
const cricket::ServerAddresses& stun_servers,
const WebVector<cricket::RelayServerConfig>& turn_servers,
IceTransportPolicy policy) {
if (port_allocator_) {
port_allocator_->set_candidate_filter(GetCandidateFilterForPolicy(policy));
port_allocator_->SetConfiguration(
stun_servers,
const_cast<WebVector<cricket::RelayServerConfig>&>(turn_servers)
.ReleaseVector(),
port_allocator_->candidate_pool_size(),
port_allocator_->prune_turn_ports());
}
if (!ice_transport_channel()) {
LOG(ERROR) << "StartGathering called, but ICE transport released";
return;
}
ice_transport_channel()->SetIceParameters(local_parameters);
ice_transport_channel()->MaybeStartGathering();
DCHECK_EQ(ice_transport_channel()->gathering_state(),
cricket::kIceGatheringGathering);
}
void IceTransportAdapterImpl::Start(
const cricket::IceParameters& remote_parameters,
cricket::IceRole role,
const Vector<cricket::Candidate>& initial_remote_candidates) {
if (!ice_transport_channel()) {
LOG(ERROR) << "Start called, but ICE transport released";
return;
}
ice_transport_channel()->SetRemoteIceParameters(remote_parameters);
ice_transport_channel()->SetIceRole(role);
for (const auto& candidate : initial_remote_candidates) {
ice_transport_channel()->AddRemoteCandidate(candidate);
}
}
void IceTransportAdapterImpl::HandleRemoteRestart(
const cricket::IceParameters& new_remote_parameters) {
if (!ice_transport_channel()) {
LOG(ERROR) << "HandleRemoteRestart called, but ICE transport released";
return;
}
ice_transport_channel()->RemoveAllRemoteCandidates();
ice_transport_channel()->SetRemoteIceParameters(new_remote_parameters);
}
void IceTransportAdapterImpl::AddRemoteCandidate(
const cricket::Candidate& candidate) {
if (!ice_transport_channel()) {
LOG(ERROR) << "AddRemoteCandidate called, but ICE transport released";
return;
}
ice_transport_channel()->AddRemoteCandidate(candidate);
}
void IceTransportAdapterImpl::SetupIceTransportChannel() {
if (!ice_transport_channel()) {
LOG(ERROR) << "SetupIceTransportChannel called, but ICE transport released";
return;
}
ice_transport_channel()->SignalGatheringState.connect(
this, &IceTransportAdapterImpl::OnGatheringStateChanged);
ice_transport_channel()->SignalCandidateGathered.connect(
this, &IceTransportAdapterImpl::OnCandidateGathered);
ice_transport_channel()->SignalIceTransportStateChanged.connect(
this, &IceTransportAdapterImpl::OnStateChanged);
ice_transport_channel()->SignalNetworkRouteChanged.connect(
this, &IceTransportAdapterImpl::OnNetworkRouteChanged);
ice_transport_channel()->SignalRoleConflict.connect(
this, &IceTransportAdapterImpl::OnRoleConflict);
}
void IceTransportAdapterImpl::OnGatheringStateChanged(
cricket::IceTransportInternal* transport) {
DCHECK_EQ(transport, ice_transport_channel());
delegate_->OnGatheringStateChanged(
ice_transport_channel()->gathering_state());
}
void IceTransportAdapterImpl::OnCandidateGathered(
cricket::IceTransportInternal* transport,
const cricket::Candidate& candidate) {
DCHECK_EQ(transport, ice_transport_channel());
delegate_->OnCandidateGathered(candidate);
}
void IceTransportAdapterImpl::OnStateChanged(
cricket::IceTransportInternal* transport) {
DCHECK_EQ(transport, ice_transport_channel());
delegate_->OnStateChanged(ice_transport_channel()->GetIceTransportState());
}
void IceTransportAdapterImpl::OnNetworkRouteChanged(
absl::optional<rtc::NetworkRoute> new_network_route) {
if (!ice_transport_channel()) {
LOG(ERROR) << "OnNetworkRouteChanged called, but ICE transport released";
return;
}
const absl::optional<const cricket::CandidatePair> selected_pair =
ice_transport_channel()->GetSelectedCandidatePair();
if (!selected_pair) {
// The selected connection will only be null if the ICE connection has
// totally failed, at which point we'll get a StateChanged signal. The
// client will implicitly clear the selected candidate pair when it receives
// the failed state change, so we don't need to give an explicit callback
// here.
return;
}
delegate_->OnSelectedCandidatePairChanged(std::make_pair(
selected_pair->local_candidate(), selected_pair->remote_candidate()));
}
static const char* IceRoleToString(cricket::IceRole role) {
switch (role) {
case cricket::ICEROLE_CONTROLLING:
return "controlling";
case cricket::ICEROLE_CONTROLLED:
return "controlled";
default:
return "unknown";
}
}
static cricket::IceRole IceRoleReversed(cricket::IceRole role) {
switch (role) {
case cricket::ICEROLE_CONTROLLING:
return cricket::ICEROLE_CONTROLLED;
case cricket::ICEROLE_CONTROLLED:
return cricket::ICEROLE_CONTROLLING;
default:
return cricket::ICEROLE_UNKNOWN;
}
}
void IceTransportAdapterImpl::OnRoleConflict(
cricket::IceTransportInternal* transport) {
DCHECK_EQ(transport, ice_transport_channel());
// This logic is copied from JsepTransportController.
cricket::IceRole reversed_role =
IceRoleReversed(ice_transport_channel()->GetIceRole());
LOG(INFO) << "Got role conflict; switching to "
<< IceRoleToString(reversed_role) << " role.";
ice_transport_channel()->SetIceRole(reversed_role);
}
} // namespace blink