Commit d78d9f90 authored by Steve Anton's avatar Steve Anton Committed by Commit Bot

RTCIceTransport: gather() implementation.

This change implements the RTCIceTransport.gather() method and
associated methods/events: getLocalCandidates(), gatheringState,
ongatheringstatechange, and onicecandidate.

The state property is also partially implemented so that the
RTCIceTransport can be stopped and garbage collected.

Bug: 864871
Change-Id: I7056764789d92dc93038a7a2279a15c850b4d299
Reviewed-on: https://chromium-review.googlesource.com/1153845
Commit-Queue: Steve Anton <steveanton@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarHarald Alvestrand <hta@chromium.org>
Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585634}
parent 748aa79f
......@@ -313,6 +313,19 @@ PeerConnectionDependencyFactory::CreatePeerConnection(
if (!GetPcFactory().get())
return nullptr;
std::unique_ptr<P2PPortAllocator> port_allocator =
CreatePortAllocator(web_frame);
return GetPcFactory()
->CreatePeerConnection(config, std::move(port_allocator), nullptr,
observer)
.get();
}
std::unique_ptr<P2PPortAllocator>
PeerConnectionDependencyFactory::CreatePortAllocator(
blink::WebLocalFrame* web_frame) {
DCHECK(web_frame);
// Copy the flag from Preference associated with this WebLocalFrame.
P2PPortAllocator::Config port_config;
uint16_t min_port = 0;
......@@ -417,16 +430,13 @@ PeerConnectionDependencyFactory::CreatePeerConnection(
} else {
network_manager.reset(new EmptyNetworkManager(network_manager_));
}
std::unique_ptr<P2PPortAllocator> port_allocator(new P2PPortAllocator(
auto port_allocator = std::make_unique<P2PPortAllocator>(
p2p_socket_dispatcher_, std::move(network_manager), socket_factory_.get(),
port_config, requesting_origin));
port_config, requesting_origin);
if (IsValidPortRange(min_port, max_port))
port_allocator->SetPortRange(min_port, max_port);
return GetPcFactory()
->CreatePeerConnection(config, std::move(port_allocator),
nullptr, observer)
.get();
return port_allocator;
}
scoped_refptr<webrtc::MediaStreamInterface>
......@@ -561,6 +571,12 @@ PeerConnectionDependencyFactory::GetWebRtcWorkerThread() const {
: nullptr;
}
rtc::Thread* PeerConnectionDependencyFactory::GetWebRtcWorkerThreadRtcThread()
const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return chrome_worker_thread_.IsRunning() ? worker_thread_ : nullptr;
}
scoped_refptr<base::SingleThreadTaskRunner>
PeerConnectionDependencyFactory::GetWebRtcSignalingThread() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
......
......@@ -42,6 +42,7 @@ namespace content {
class IpcNetworkManager;
class IpcPacketSocketFactory;
class P2PPortAllocator;
class WebRtcAudioDeviceImpl;
// Object factory for RTC PeerConnections.
......@@ -81,6 +82,11 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
blink::WebLocalFrame* web_frame,
webrtc::PeerConnectionObserver* observer);
// Creates a PortAllocator that uses Chrome IPC sockets and enforces privacy
// controls according to the permissions granted on the page.
virtual std::unique_ptr<P2PPortAllocator> CreatePortAllocator(
blink::WebLocalFrame* web_frame);
// Creates a libjingle representation of a Session description. Used by a
// RTCPeerConnectionHandler instance.
virtual webrtc::SessionDescriptionInterface* CreateSessionDescription(
......@@ -105,6 +111,8 @@ class CONTENT_EXPORT PeerConnectionDependencyFactory
void EnsureInitialized();
scoped_refptr<base::SingleThreadTaskRunner> GetWebRtcWorkerThread() const;
// TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component.
rtc::Thread* GetWebRtcWorkerThreadRtcThread() const;
virtual scoped_refptr<base::SingleThreadTaskRunner> GetWebRtcSignalingThread()
const;
......
......@@ -65,6 +65,7 @@
#include "content/renderer/media_capture_from_element/html_video_element_capturer_source.h"
#include "content/renderer/media_recorder/media_recorder_handler.h"
#include "content/renderer/mojo/blink_interface_provider_impl.h"
#include "content/renderer/p2p/port_allocator.h"
#include "content/renderer/push_messaging/push_provider.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/storage_util.h"
......@@ -842,6 +843,38 @@ bool RendererBlinkPlatformImpl::SetSandboxEnabledForTesting(bool enable) {
//------------------------------------------------------------------------------
scoped_refptr<base::SingleThreadTaskRunner>
RendererBlinkPlatformImpl::GetWebRtcWorkerThread() {
RenderThreadImpl* render_thread = RenderThreadImpl::current();
DCHECK(render_thread);
PeerConnectionDependencyFactory* rtc_dependency_factory =
render_thread->GetPeerConnectionDependencyFactory();
rtc_dependency_factory->EnsureInitialized();
return rtc_dependency_factory->GetWebRtcWorkerThread();
}
rtc::Thread* RendererBlinkPlatformImpl::GetWebRtcWorkerThreadRtcThread() {
RenderThreadImpl* render_thread = RenderThreadImpl::current();
DCHECK(render_thread);
PeerConnectionDependencyFactory* rtc_dependency_factory =
render_thread->GetPeerConnectionDependencyFactory();
rtc_dependency_factory->EnsureInitialized();
return rtc_dependency_factory->GetWebRtcWorkerThreadRtcThread();
}
std::unique_ptr<cricket::PortAllocator>
RendererBlinkPlatformImpl::CreateWebRtcPortAllocator(
blink::WebLocalFrame* frame) {
RenderThreadImpl* render_thread = RenderThreadImpl::current();
DCHECK(render_thread);
PeerConnectionDependencyFactory* rtc_dependency_factory =
render_thread->GetPeerConnectionDependencyFactory();
rtc_dependency_factory->EnsureInitialized();
return rtc_dependency_factory->CreatePortAllocator(frame);
}
//------------------------------------------------------------------------------
std::unique_ptr<WebCanvasCaptureHandler>
RendererBlinkPlatformImpl::CreateCanvasCaptureHandler(
const WebSize& size,
......
......@@ -162,6 +162,10 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
std::unique_ptr<blink::WebMediaStreamCenter> CreateMediaStreamCenter()
override;
scoped_refptr<base::SingleThreadTaskRunner> GetWebRtcWorkerThread() override;
rtc::Thread* GetWebRtcWorkerThreadRtcThread() override;
std::unique_ptr<cricket::PortAllocator> CreateWebRtcPortAllocator(
blink::WebLocalFrame* frame) override;
std::unique_ptr<blink::WebCanvasCaptureHandler> CreateCanvasCaptureHandler(
const blink::WebSize& size,
double frame_rate,
......
......@@ -9,6 +9,12 @@
// These tests are based on the following extension specification:
// https://w3c.github.io/webrtc-ice/
function makeIceTransport(t) {
const iceTransport = new RTCIceTransport();
t.add_cleanup(() => iceTransport.stop());
return iceTransport;
}
test(() => {
const iceTransport = new RTCIceTransport();
}, 'RTCIceTransport constructor does not throw.');
......@@ -25,10 +31,98 @@ test(() => {
'Expect no remote candidates');
assert_equals(iceTransport.getSelectedCandidatePair(), null,
'Expect no selected candidate pair');
assert_equals(iceTransport.getLocalParameters(), null,
'Expect no local parameters');
assert_not_equals(iceTransport.getLocalParameters(), null,
'Expect local parameters generated');
assert_equals(iceTransport.getRemoteParameters(), null,
'Expect no remote parameters');
}, 'RTCIceTransport initial properties are set.');
test(t => {
const iceTransport = makeIceTransport(t);
assert_throws(new TypeError(), () =>
iceTransport.gather({ iceServers: null }));
}, 'gather() with { iceServers: null } should throw TypeError');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({ iceServers: undefined });
}, 'gather() with { iceServers: undefined } should succeed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({ iceServers: [{
urls: ['turns:turn.example.org', 'turn:turn.example.net'],
username: 'user',
credential: 'cred',
}] });
}, 'gather() with one turns server, one turn server, username, credential' +
' should succeed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({ iceServers: [{
urls: ['stun:stun1.example.net', 'stun:stun2.example.net'],
}] });
}, 'gather() with 2 stun servers should succeed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.stop();
assert_throws('InvalidStateError', () => iceTransport.gather({}));
}, 'gather() throws if closed');
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({});
assert_equals(iceTransport.gatheringState, 'gathering');
}, `gather() transitions gatheringState to 'gathering'`);
test(t => {
const iceTransport = makeIceTransport(t);
iceTransport.gather({});
assert_throws('InvalidStateError', () => iceTransport.gather({}));
}, 'gather() throws if called twice');
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport, 'gatheringstatechange');
iceTransport.gather({});
await watcher.wait_for('gatheringstatechange');
assert_equals(iceTransport.gatheringState, 'complete');
}, `eventually transition gatheringState to 'complete'`);
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport,
[ 'icecandidate', 'gatheringstatechange' ]);
iceTransport.gather({});
let candidate;
do {
({ candidate } = await watcher.wait_for('icecandidate'));
} while (candidate !== null);
assert_equals(iceTransport.gatheringState, 'gathering');
await watcher.wait_for('gatheringstatechange');
assert_equals(iceTransport.gatheringState, 'complete');
}, 'onicecandidate fires with null candidate before gatheringState' +
` transitions to 'complete'`);
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport, 'icecandidate');
iceTransport.gather({});
const { candidate } = await watcher.wait_for('icecandidate');
assert_not_equals(candidate.candidate, '');
assert_array_equals(iceTransport.getLocalCandidates(), [candidate]);
}, 'gather() returns at least one host candidate');
promise_test(async t => {
const iceTransport = makeIceTransport(t);
const watcher = new EventWatcher(t, iceTransport, 'icecandidate');
iceTransport.gather({ gatherPolicy: 'relay' });
const { candidate } = await watcher.wait_for('icecandidate');
assert_equals(candidate, null);
assert_array_equals(iceTransport.getLocalCandidates(), []);
}, `gather() returns no candidates with { gatherPolicy: 'relay'} and no turn` +
' servers');
</script>
......@@ -321,10 +321,10 @@ FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit prope
FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "getRemoteCertificates()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onstatechange" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onerror" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL RTCIceTransport interface: existence and properties of interface object assert_equals: prototype of RTCIceTransport is not EventTarget expected function "function EventTarget() { [native code] }" but got function "function () { [native code] }"
FAIL RTCIceTransport interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function () { [native code] }" did not throw
PASS RTCIceTransport interface object length
PASS RTCIceTransport interface object name
FAIL RTCIceTransport interface: existence and properties of interface prototype object assert_equals: prototype of RTCIceTransport.prototype is not EventTarget.prototype expected object "[object EventTarget]" but got object "[object Object]"
PASS RTCIceTransport interface: existence and properties of interface prototype object
PASS RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property
PASS RTCIceTransport interface: existence and properties of interface prototype object's @@unscopables property
PASS RTCIceTransport interface: attribute role
......@@ -337,7 +337,7 @@ PASS RTCIceTransport interface: operation getSelectedCandidatePair()
PASS RTCIceTransport interface: operation getLocalParameters()
PASS RTCIceTransport interface: operation getRemoteParameters()
FAIL RTCIceTransport interface: attribute onstatechange assert_true: The prototype object must have a property "onstatechange" expected true got false
FAIL RTCIceTransport interface: attribute ongatheringstatechange assert_true: The prototype object must have a property "ongatheringstatechange" expected true got false
PASS RTCIceTransport interface: attribute ongatheringstatechange
FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_true: The prototype object must have a property "onselectedcandidatepairchange" expected true got false
FAIL RTCIceTransport must be primary interface of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL Stringification of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
......
......@@ -321,10 +321,10 @@ FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit prope
FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "getRemoteCertificates()" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onstatechange" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL RTCDtlsTransport interface: idlTestObjects.dtlsTransport must inherit property "onerror" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL RTCIceTransport interface: existence and properties of interface object assert_equals: prototype of RTCIceTransport is not EventTarget expected function "function EventTarget() { [native code] }" but got function "function () { [native code] }"
FAIL RTCIceTransport interface: existence and properties of interface object assert_throws: interface object didn't throw TypeError when called as a constructor function "function () { [native code] }" did not throw
PASS RTCIceTransport interface object length
PASS RTCIceTransport interface object name
FAIL RTCIceTransport interface: existence and properties of interface prototype object assert_equals: prototype of RTCIceTransport.prototype is not EventTarget.prototype expected object "[object EventTarget]" but got object "[object Object]"
PASS RTCIceTransport interface: existence and properties of interface prototype object
PASS RTCIceTransport interface: existence and properties of interface prototype object's "constructor" property
PASS RTCIceTransport interface: existence and properties of interface prototype object's @@unscopables property
PASS RTCIceTransport interface: attribute role
......@@ -337,7 +337,7 @@ PASS RTCIceTransport interface: operation getSelectedCandidatePair()
PASS RTCIceTransport interface: operation getLocalParameters()
PASS RTCIceTransport interface: operation getRemoteParameters()
FAIL RTCIceTransport interface: attribute onstatechange assert_true: The prototype object must have a property "onstatechange" expected true got false
FAIL RTCIceTransport interface: attribute ongatheringstatechange assert_true: The prototype object must have a property "ongatheringstatechange" expected true got false
PASS RTCIceTransport interface: attribute ongatheringstatechange
FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_true: The prototype object must have a property "onselectedcandidatepairchange" expected true got false
FAIL RTCIceTransport must be primary interface of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL Stringification of idlTestObjects.iceTransport assert_equals: wrong typeof object expected "object" but got "undefined"
......
......@@ -5430,17 +5430,23 @@ interface RTCIceCandidate
setter candidate
setter sdpMLineIndex
setter sdpMid
interface RTCIceTransport
interface RTCIceTransport : EventTarget
attribute @@toStringTag
getter gatheringState
getter ongatheringstatechange
getter onicecandidate
getter role
getter state
method constructor
method gather
method getLocalCandidates
method getLocalParameters
method getRemoteCandidates
method getRemoteParameters
method getSelectedCandidatePair
method stop
setter ongatheringstatechange
setter onicecandidate
interface RTCPeerConnection : EventTarget
static method generateCertificate
attribute @@toStringTag
......
......@@ -62,6 +62,7 @@
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_url_loader.h"
#include "third_party/blink/public/platform/web_url_loader_factory.h"
#include "third_party/webrtc/p2p/base/portallocator.h"
namespace base {
class SingleThreadTaskRunner;
......@@ -71,6 +72,10 @@ namespace gpu {
class GpuMemoryBufferManager;
}
namespace rtc {
class Thread;
}
namespace service_manager {
class Connector;
class InterfaceProvider;
......@@ -99,6 +104,7 @@ class WebDatabaseObserver;
class WebFileSystem;
class WebGraphicsContext3DProvider;
class WebImageCaptureFrameGrabber;
class WebLocalFrame;
class WebMIDIAccessor;
class WebMIDIAccessorClient;
class WebMediaCapabilitiesClient;
......@@ -600,6 +606,24 @@ class BLINK_PLATFORM_EXPORT Platform {
// resources.
virtual std::unique_ptr<WebMediaStreamCenter> CreateMediaStreamCenter();
// Returns the SingleThreadTaskRunner suitable for running WebRTC networking.
// An rtc::Thread will have already been created.
// May return null if WebRTC functionality is not implemented.
virtual scoped_refptr<base::SingleThreadTaskRunner> GetWebRtcWorkerThread() {
return nullptr;
}
// Returns the rtc::Thread instance associated with the WebRTC worker thread.
// TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component.
// May return null if WebRTC functionality is not implemented.
virtual rtc::Thread* GetWebRtcWorkerThreadRtcThread() { return nullptr; }
// May return null if WebRTC functionality is not implemented.
virtual std::unique_ptr<cricket::PortAllocator> CreateWebRtcPortAllocator(
WebLocalFrame* frame) {
return nullptr;
}
// Creates a WebCanvasCaptureHandler to capture Canvas output.
virtual std::unique_ptr<WebCanvasCaptureHandler>
CreateCanvasCaptureHandler(const WebSize&, double, WebMediaStreamTrack*);
......
......@@ -126,6 +126,7 @@
"fullscreenerror",
"gamepadconnected",
"gamepaddisconnected",
"gatheringstatechange",
"gattserverdisconnected",
"geofenceenter",
"geofenceleave",
......
......@@ -162,6 +162,8 @@ target("jumbo_" + modules_target_type, "modules") {
"//third_party/blink/renderer/modules/webusb",
"//third_party/blink/renderer/modules/xr",
"//third_party/icu",
"//third_party/webrtc/pc:libjingle_peerconnection",
"//third_party/webrtc_overrides:init_webrtc",
"//third_party/zlib",
]
......
......@@ -30,6 +30,7 @@
"modules/netinfo/NetworkInformation",
"modules/notifications/Notification",
"modules/payments/PaymentRequest",
"modules/peerconnection/RTCIceTransport",
"modules/permissions/PermissionStatus",
"modules/picture_in_picture/HTMLVideoElementPictureInPicture",
"modules/picture_in_picture/PictureInPictureWindow",
......
......@@ -592,6 +592,7 @@ modules_dictionary_idl_files =
"peerconnection/rtc_data_channel_init.idl",
"peerconnection/rtc_ice_candidate_init.idl",
"peerconnection/rtc_ice_candidate_pair.idl",
"peerconnection/rtc_ice_gather_options.idl",
"peerconnection/rtc_ice_parameters.idl",
"peerconnection/rtc_ice_server.idl",
"peerconnection/rtc_offer_answer_options.idl",
......
......@@ -6,6 +6,12 @@ import("//third_party/blink/renderer/modules/modules.gni")
blink_modules_sources("peerconnection") {
sources = [
"adapters/ice_transport_host.cc",
"adapters/ice_transport_host.h",
"adapters/ice_transport_proxy.cc",
"adapters/ice_transport_proxy.h",
"adapters/web_rtc_cross_thread_copier.cc",
"adapters/web_rtc_cross_thread_copier.h",
"rtc_certificate.cc",
"rtc_certificate.h",
"rtc_data_channel.cc",
......
## WebRTC API Adapters
This directory contains code that wraps components of the WebRTC native API in
classes that expose an API specialized for implementing the Web API. Some of
these adapters also allow the WebRTC component to be safely used from a remote
thread.
### Blink Types
Blink types (like AtomicString, HeapVector, etc.) should not be used inside this
directory. The bindings in the parent directory are responsible for converting
the Blink binding types to the corresponding STL/WebRTC types before interacting
with the adapters.
// 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_host.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/web_task_runner.h"
namespace blink {
IceTransportHost::IceTransportHost(
scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
base::WeakPtr<IceTransportProxy> proxy,
std::unique_ptr<cricket::PortAllocator> port_allocator)
: proxy_thread_(std::move(proxy_thread)),
port_allocator_(std::move(port_allocator)),
proxy_(std::move(proxy)) {
DETACH_FROM_THREAD(thread_checker_);
DCHECK(proxy_thread_);
DCHECK(proxy_);
DCHECK(port_allocator_);
}
IceTransportHost::~IceTransportHost() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
void IceTransportHost::Initialize(rtc::Thread* host_thread_rtc_thread) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// TODO(bugs.webrtc.org/9419): Remove once WebRTC can be built as a component.
if (!rtc::ThreadManager::Instance()->CurrentThread()) {
rtc::ThreadManager::Instance()->SetCurrentThread(host_thread_rtc_thread);
}
// 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();
transport_ = std::make_unique<cricket::P2PTransportChannel>(
"", 0, port_allocator_.get());
transport_->SignalGatheringState.connect(
this, &IceTransportHost::OnGatheringStateChanged);
transport_->SignalCandidateGathered.connect(
this, &IceTransportHost::OnCandidateGathered);
// 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.
transport_->SetIceTiebreaker(rtc::CreateRandomId64());
}
void IceTransportHost::StartGathering(
const cricket::IceParameters& local_parameters,
const cricket::ServerAddresses& stun_servers,
const std::vector<cricket::RelayServerConfig>& turn_servers,
int32_t candidate_filter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
port_allocator_->set_candidate_filter(candidate_filter);
port_allocator_->SetConfiguration(stun_servers, turn_servers,
port_allocator_->candidate_pool_size(),
port_allocator_->prune_turn_ports());
transport_->SetIceParameters(local_parameters);
transport_->MaybeStartGathering();
DCHECK_EQ(transport_->gathering_state(), cricket::kIceGatheringGathering);
}
void IceTransportHost::OnGatheringStateChanged(
cricket::IceTransportInternal* transport) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_EQ(transport, transport_.get());
PostCrossThreadTask(
*proxy_thread_, FROM_HERE,
CrossThreadBind(&IceTransportProxy::OnGatheringStateChanged, proxy_,
transport_->gathering_state()));
}
void IceTransportHost::OnCandidateGathered(
cricket::IceTransportInternal* transport,
const cricket::Candidate& candidate) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK_EQ(transport, transport_.get());
PostCrossThreadTask(*proxy_thread_, FROM_HERE,
CrossThreadBind(&IceTransportProxy::OnCandidateGathered,
proxy_, candidate));
}
} // namespace blink
// 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_HOST_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_HOST_H_
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "third_party/webrtc/p2p/base/p2ptransportchannel.h"
namespace rtc {
class Thread;
}
namespace blink {
class IceTransportProxy;
// This class is the host side correspondent to the IceTransportProxy. See the
// IceTransportProxy documentation for background. This class lives on the host
// thread and proxies calls between the IceTransportProxy and the
// P2PTransportChannel (which is single-threaded).
//
// proxy thread host thread
// +------------------+ unique_ptr +------------------------------+
// | | =========> | |
// | client <-> Proxy | | Host <-> P2PTransportChannel |
// | | <--------- | |
// +------------------+ WeakPtr +------------------------------+
//
// Since the client code controls the Proxy lifetime, the Proxy has a unique_ptr
// to the Host that lives on the host thread. The unique_ptr has an
// OnTaskRunnerDeleter so that when the Proxy is destroyed a task will be queued
// to delete the Host as well (and the P2PTransportChannel with it). The Host
// needs a pointer back to the Proxy to post callbacks, and by using a WeakPtr
// any callbacks run on the proxy thread after the proxy has been deleted will
// be safely dropped.
//
// The Host can be constructed on any thread but after that point all methods
// must be called on the host thread.
class IceTransportHost final : public sigslot::has_slots<> {
public:
IceTransportHost(scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
base::WeakPtr<IceTransportProxy> proxy,
std::unique_ptr<cricket::PortAllocator> port_allocator);
~IceTransportHost() override;
void Initialize(rtc::Thread* host_thread_rtc_thread);
void StartGathering(
const cricket::IceParameters& local_parameters,
const cricket::ServerAddresses& stun_servers,
const std::vector<cricket::RelayServerConfig>& turn_servers,
int32_t candidate_filter);
private:
// Callbacks from P2PTransportChannel.
void OnGatheringStateChanged(cricket::IceTransportInternal* transport);
void OnCandidateGathered(cricket::IceTransportInternal* transport,
const cricket::Candidate& candidate);
const scoped_refptr<base::SingleThreadTaskRunner> proxy_thread_;
std::unique_ptr<cricket::PortAllocator> port_allocator_;
std::unique_ptr<cricket::P2PTransportChannel> transport_;
base::WeakPtr<IceTransportProxy> proxy_;
THREAD_CHECKER(thread_checker_);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_HOST_H_
// 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_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_host.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/web_rtc_cross_thread_copier.h"
#include "third_party/blink/renderer/platform/cross_thread_functional.h"
#include "third_party/blink/renderer/platform/web_task_runner.h"
namespace blink {
IceTransportProxy::IceTransportProxy(
FrameScheduler* frame_scheduler,
scoped_refptr<base::SingleThreadTaskRunner> host_thread,
rtc::Thread* host_thread_rtc_thread,
Delegate* delegate,
std::unique_ptr<cricket::PortAllocator> port_allocator)
: host_thread_(std::move(host_thread)),
host_(nullptr, base::OnTaskRunnerDeleter(host_thread_)),
delegate_(delegate),
connection_handle_for_scheduler_(
frame_scheduler->OnActiveConnectionCreated()),
weak_ptr_factory_(this) {
DCHECK(host_thread_);
DCHECK(delegate_);
scoped_refptr<base::SingleThreadTaskRunner> proxy_thread =
frame_scheduler->GetTaskRunner(TaskType::kNetworking);
DCHECK(proxy_thread->BelongsToCurrentThread());
// Wait to initialize the host until the weak_ptr_factory_ is initialized.
// The IceTransportHost is constructed on the proxy thread but should only be
// interacted with via PostTask to the host thread. The OnTaskRunnerDeleter
// (configured above) will ensure it gets deleted on the host thread.
host_.reset(new IceTransportHost(proxy_thread, weak_ptr_factory_.GetWeakPtr(),
std::move(port_allocator)));
PostCrossThreadTask(
*host_thread_, FROM_HERE,
CrossThreadBind(&IceTransportHost::Initialize,
CrossThreadUnretained(host_.get()),
CrossThreadUnretained(host_thread_rtc_thread)));
}
IceTransportProxy::~IceTransportProxy() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Note: The IceTransportHost will be deleted on the host thread.
}
void IceTransportProxy::StartGathering(
const cricket::IceParameters& local_parameters,
const cricket::ServerAddresses& stun_servers,
const std::vector<cricket::RelayServerConfig>& turn_servers,
int32_t candidate_filter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
PostCrossThreadTask(
*host_thread_, FROM_HERE,
CrossThreadBind(&IceTransportHost::StartGathering,
CrossThreadUnretained(host_.get()), local_parameters,
stun_servers, turn_servers, candidate_filter));
}
void IceTransportProxy::OnGatheringStateChanged(
cricket::IceGatheringState new_state) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
delegate_->OnGatheringStateChanged(new_state);
}
void IceTransportProxy::OnCandidateGathered(
const cricket::Candidate& candidate) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
delegate_->OnCandidateGathered(candidate);
}
} // namespace blink
// 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_PROXY_H_
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/webrtc/p2p/base/p2ptransportchannel.h"
namespace rtc {
class Thread;
}
namespace blink {
class IceTransportHost;
// This class allows the ICE implementation (P2PTransportChannel) to run on a
// thread different from the thread from which it is controlled. All
// interactions with the ICE implementation happen asynchronously.
//
// Terminology:
// - Proxy thread: Thread from which the P2PTransportChannel is controlled. This
// is the thread on which the IceTransportProxy is created.
// - Host thread: Thread on which the P2PTransportChannel runs. This is usually
// the WebRTC worker thread and is specified when creating the
// IceTransportProxy.
//
// The client must create the IceTransportProxy on the same thread it wishes
// to control it from. The Proxy will manage all cross-thread interactions; the
// client should call all methods from the proxy thread and all callbacks will
// be run on the proxy thread.
class IceTransportProxy final {
public:
// Delegate for receiving callbacks from the ICE implementation. These all run
// on the proxy thread.
class Delegate {
public:
virtual ~Delegate() = default;
virtual void OnGatheringStateChanged(cricket::IceGatheringState new_state) {
}
virtual void OnCandidateGathered(const cricket::Candidate& candidate) {}
};
// Construct a Proxy with the underlying ICE implementation running on the
// given host thread and callbacks serviced by the given delegate.
// The P2PTransportChannel will be created with the given PortAllocator.
// The delegate must outlive the IceTransportProxy.
IceTransportProxy(FrameScheduler* frame_scheduler,
scoped_refptr<base::SingleThreadTaskRunner> host_thread,
rtc::Thread* host_thread_rtc_thread,
Delegate* delegate,
std::unique_ptr<cricket::PortAllocator> port_allocator);
~IceTransportProxy();
void StartGathering(
const cricket::IceParameters& local_parameters,
const cricket::ServerAddresses& stun_servers,
const std::vector<cricket::RelayServerConfig>& turn_servers,
int32_t candidate_filter);
private:
// Callbacks from RTCIceTransportHost.
friend class IceTransportHost;
void OnGatheringStateChanged(cricket::IceGatheringState new_state);
void OnCandidateGathered(const cricket::Candidate& candidate);
const scoped_refptr<base::SingleThreadTaskRunner> host_thread_;
// Since the Host is deleted on the host thread (via OnTaskRunnerDeleter), as
// long as this is alive it is safe to post tasks to it (using unretained).
std::unique_ptr<IceTransportHost, base::OnTaskRunnerDeleter> host_;
Delegate* const delegate_;
// This handle notifies scheduler about an active connection associated
// with a frame. Handle should be destroyed when connection is closed.
// This should have the same lifetime as |proxy_|.
std::unique_ptr<FrameScheduler::ActiveConnectionHandle>
connection_handle_for_scheduler_;
THREAD_CHECKER(thread_checker_);
// Must be the last member.
base::WeakPtrFactory<IceTransportProxy> weak_ptr_factory_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_ICE_TRANSPORT_PROXY_H_
// 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/web_rtc_cross_thread_copier.h"
// 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_
// This file defines specializations for the CrossThreadCopier that allow WebRTC
// types to be passed across threads using their copy constructors.
#include <set>
#include <vector>
#include "third_party/blink/renderer/platform/cross_thread_copier.h"
namespace cricket {
class Candidate;
struct IceParameters;
struct RelayServerConfig;
} // namespace cricket
namespace rtc {
class SocketAddress;
}
namespace blink {
template <>
struct CrossThreadCopier<cricket::IceParameters>
: public CrossThreadCopierPassThrough<cricket::IceParameters> {
STATIC_ONLY(CrossThreadCopier);
};
template <>
struct CrossThreadCopier<std::set<rtc::SocketAddress>>
: public CrossThreadCopierPassThrough<std::set<rtc::SocketAddress>> {
STATIC_ONLY(CrossThreadCopier);
};
template <>
struct CrossThreadCopier<std::vector<cricket::RelayServerConfig>>
: public CrossThreadCopierPassThrough<
std::vector<cricket::RelayServerConfig>> {
STATIC_ONLY(CrossThreadCopier);
};
template <>
struct CrossThreadCopier<cricket::Candidate>
: public CrossThreadCopierPassThrough<cricket::Candidate> {
STATIC_ONLY(CrossThreadCopier);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_
// 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.
// https://w3c.github.io/webrtc-ice/#dom-rtcicegatheroptions
dictionary RTCIceGatherOptions {
RTCIceTransportPolicy gatherPolicy = "all";
sequence<RTCIceServer> iceServers;
};
......@@ -4,28 +4,89 @@
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_transport.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_thread.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_error_util.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_gather_options.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_server.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_ice_event_init.h"
#include "third_party/webrtc/api/peerconnectioninterface.h"
#include "third_party/webrtc/p2p/base/portallocator.h"
#include "third_party/webrtc/p2p/base/transportdescription.h"
#include "third_party/webrtc/pc/iceserverparsing.h"
#include "third_party/webrtc/pc/webrtcsdp.h"
namespace blink {
RTCIceTransport* RTCIceTransport::Create() {
return new RTCIceTransport();
RTCIceTransport* RTCIceTransport::Create(ExecutionContext* context) {
return new RTCIceTransport(context);
}
RTCIceTransport::RTCIceTransport() = default;
RTCIceTransport::RTCIceTransport(ExecutionContext* context)
: ContextLifecycleObserver(context) {
Document* document = ToDocument(GetExecutionContext());
LocalFrame* frame = document->GetFrame();
DCHECK(frame);
std::unique_ptr<cricket::PortAllocator> port_allocator =
Platform::Current()->CreateWebRtcPortAllocator(
WebLocalFrame::FrameForCurrentContext());
proxy_.reset(new IceTransportProxy(
frame->GetFrameScheduler(), Platform::Current()->GetWebRtcWorkerThread(),
Platform::Current()->GetWebRtcWorkerThreadRtcThread(), this,
std::move(port_allocator)));
GenerateLocalParameters();
}
RTCIceTransport::~RTCIceTransport() {
DCHECK(!proxy_);
}
String RTCIceTransport::role() const {
return String();
}
String RTCIceTransport::state() const {
return "new";
switch (state_) {
case RTCIceTransportState::kNew:
return "new";
case RTCIceTransportState::kChecking:
return "checking";
case RTCIceTransportState::kConnected:
return "connected";
case RTCIceTransportState::kCompleted:
return "completed";
case RTCIceTransportState::kDisconnected:
return "disconnected";
case RTCIceTransportState::kFailed:
return "failed";
case RTCIceTransportState::kClosed:
return "closed";
}
NOTREACHED();
return g_empty_string;
}
String RTCIceTransport::gatheringState() const {
return "new";
switch (gathering_state_) {
case cricket::kIceGatheringNew:
return "new";
case cricket::kIceGatheringGathering:
return "gathering";
case cricket::kIceGatheringComplete:
return "complete";
default:
NOTREACHED();
return g_empty_string;
}
}
const HeapVector<Member<RTCIceCandidate>>& RTCIceTransport::getLocalCandidates()
......@@ -45,7 +106,7 @@ void RTCIceTransport::getSelectedCandidatePair(
void RTCIceTransport::getLocalParameters(
base::Optional<RTCIceParameters>& result) const {
result = base::nullopt;
result = local_parameters_;
}
void RTCIceTransport::getRemoteParameters(
......@@ -53,11 +114,159 @@ void RTCIceTransport::getRemoteParameters(
result = base::nullopt;
}
static webrtc::PeerConnectionInterface::IceServer ConvertIceServer(
const RTCIceServer& ice_server) {
webrtc::PeerConnectionInterface::IceServer converted_ice_server;
// Prefer standardized 'urls' field over deprecated 'url' field.
Vector<String> url_strings;
if (ice_server.hasURLs()) {
if (ice_server.urls().IsString()) {
url_strings.push_back(ice_server.urls().GetAsString());
} else if (ice_server.urls().IsStringSequence()) {
url_strings = ice_server.urls().GetAsStringSequence();
}
} else if (ice_server.hasURL()) {
url_strings.push_back(ice_server.url());
}
for (const String& url_string : url_strings) {
converted_ice_server.urls.push_back(WebString(url_string).Utf8());
}
converted_ice_server.username = WebString(ice_server.username()).Utf8();
converted_ice_server.password = WebString(ice_server.credential()).Utf8();
return converted_ice_server;
}
static cricket::IceParameters ConvertIceParameters(
const RTCIceParameters& ice_parameters) {
cricket::IceParameters converted_ice_parameters;
converted_ice_parameters.ufrag =
WebString(ice_parameters.usernameFragment()).Utf8();
converted_ice_parameters.pwd = WebString(ice_parameters.password()).Utf8();
return converted_ice_parameters;
}
static std::vector<webrtc::PeerConnectionInterface::IceServer>
ConvertIceServers(const HeapVector<RTCIceServer>& ice_servers) {
std::vector<webrtc::PeerConnectionInterface::IceServer> converted_ice_servers;
for (const RTCIceServer& ice_server : ice_servers) {
converted_ice_servers.push_back(ConvertIceServer(ice_server));
}
return converted_ice_servers;
}
void RTCIceTransport::gather(const RTCIceGatherOptions& options,
ExceptionState& exception_state) {
if (RaiseExceptionIfClosed(exception_state)) {
return;
}
// TODO(github.com/w3c/webrtc-ice/issues/7): Possibly support calling gather()
// more than once.
if (gathering_state_ != cricket::kIceGatheringNew) {
exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
"Can only call gather() once.");
return;
}
std::vector<webrtc::PeerConnectionInterface::IceServer> ice_servers;
if (options.hasIceServers()) {
ice_servers = ConvertIceServers(options.iceServers());
}
cricket::ServerAddresses stun_servers;
std::vector<cricket::RelayServerConfig> turn_servers;
webrtc::RTCErrorType error_type =
webrtc::ParseIceServers(ice_servers, &stun_servers, &turn_servers);
if (error_type != webrtc::RTCErrorType::NONE) {
ThrowExceptionFromRTCError(
webrtc::RTCError(error_type, "Invalid ICE server URL(s)."),
exception_state);
return;
}
gathering_state_ = cricket::kIceGatheringGathering;
uint32_t candidate_filter = cricket::CF_ALL;
if (options.gatherPolicy() == "relay") {
candidate_filter = cricket::CF_RELAY;
} else {
DCHECK_EQ(options.gatherPolicy(), "all");
}
proxy_->StartGathering(ConvertIceParameters(local_parameters_), stun_servers,
turn_servers, candidate_filter);
}
void RTCIceTransport::stop() {
if (IsClosed()) {
return;
}
state_ = RTCIceTransportState::kClosed;
proxy_.reset();
}
void RTCIceTransport::GenerateLocalParameters() {
local_parameters_.setUsernameFragment(
WebString::FromUTF8(rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH)));
local_parameters_.setPassword(
WebString::FromUTF8(rtc::CreateRandomString(cricket::ICE_PWD_LENGTH)));
}
void RTCIceTransport::OnGatheringStateChanged(
cricket::IceGatheringState new_state) {
if (new_state == gathering_state_) {
return;
}
if (new_state == cricket::kIceGatheringComplete) {
// Generate a null ICE candidate to signal the end of candidates.
DispatchEvent(*RTCPeerConnectionIceEvent::Create(nullptr));
}
gathering_state_ = new_state;
DispatchEvent(*Event::Create(EventTypeNames::gatheringstatechange));
}
void RTCIceTransport::OnCandidateGathered(
const cricket::Candidate& parsed_candidate) {
RTCIceCandidate* candidate =
RTCIceCandidate::Create(WebRTCICECandidate::Create(
WebString::FromUTF8(webrtc::SdpSerializeCandidate(parsed_candidate)),
g_empty_string, 0));
local_candidates_.push_back(candidate);
RTCPeerConnectionIceEventInit event_init;
event_init.setCandidate(candidate);
DispatchEvent(*RTCPeerConnectionIceEvent::Create(EventTypeNames::icecandidate,
event_init));
}
bool RTCIceTransport::RaiseExceptionIfClosed(
ExceptionState& exception_state) const {
if (IsClosed()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"The RTCIceTransport's state is 'closed'.");
return true;
}
return false;
}
const AtomicString& RTCIceTransport::InterfaceName() const {
return EventTargetNames::RTCIceTransport;
}
ExecutionContext* RTCIceTransport::GetExecutionContext() const {
return ContextLifecycleObserver::GetExecutionContext();
}
void RTCIceTransport::ContextDestroyed(ExecutionContext*) {
stop();
}
bool RTCIceTransport::HasPendingActivity() const {
// Only allow the RTCIceTransport to be garbage collected if the ICE
// implementation is not active.
return static_cast<bool>(proxy_);
}
void RTCIceTransport::Trace(blink::Visitor* visitor) {
visitor->Trace(local_candidates_);
visitor->Trace(remote_candidates_);
visitor->Trace(selected_candidate_pair_);
ScriptWrappable::Trace(visitor);
EventTargetWithInlineData::Trace(visitor);
ContextLifecycleObserver::Trace(visitor);
}
} // namespace blink
......@@ -5,20 +5,52 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_RTC_ICE_TRANSPORT_H_
#include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_rtc_ice_candidate_pair.h"
#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
#include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/modules/peerconnection/adapters/ice_transport_proxy.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_candidate_pair.h"
#include "third_party/blink/renderer/modules/peerconnection/rtc_ice_parameters.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
namespace blink {
class ExceptionState;
class RTCIceCandidate;
class RTCIceGatherOptions;
enum class RTCIceTransportState {
kNew,
kChecking,
kConnected,
kCompleted,
kDisconnected,
kFailed,
kClosed
};
// Blink bindings for the RTCIceTransport JavaScript object.
class MODULES_EXPORT RTCIceTransport final : public ScriptWrappable {
//
// This class uses the IceTransportProxy to run and interact with the WebRTC
// ICE implementation running on the WebRTC worker thread managed by //content
// (called network_thread here).
//
// This object inherits from ActiveScriptWrappable since it must be kept alive
// while the ICE implementation is active, regardless of the number of
// JavaScript references held to it.
class MODULES_EXPORT RTCIceTransport final
: public EventTargetWithInlineData,
public ActiveScriptWrappable<RTCIceTransport>,
public ContextLifecycleObserver,
private IceTransportProxy::Delegate {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(RTCIceTransport);
public:
static RTCIceTransport* Create();
static RTCIceTransport* Create(ExecutionContext* context);
~RTCIceTransport() override;
// rtc_ice_transport.idl
String role() const;
......@@ -30,16 +62,52 @@ class MODULES_EXPORT RTCIceTransport final : public ScriptWrappable {
base::Optional<RTCIceCandidatePair>& result) const;
void getLocalParameters(base::Optional<RTCIceParameters>& result) const;
void getRemoteParameters(base::Optional<RTCIceParameters>& result) const;
void gather(const RTCIceGatherOptions& options,
ExceptionState& exception_state);
void stop();
DEFINE_ATTRIBUTE_EVENT_LISTENER(gatheringstatechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(icecandidate);
// EventTarget overrides.
const AtomicString& InterfaceName() const override;
ExecutionContext* GetExecutionContext() const override;
// ContextLifecycleObserver overrides.
void ContextDestroyed(ExecutionContext*) override;
// ActiveScriptWrappable overrides.
bool HasPendingActivity() const override;
// For garbage collection.
void Trace(blink::Visitor* visitor) override;
private:
RTCIceTransport();
explicit RTCIceTransport(ExecutionContext* context);
// IceTransportProxy::Delegate overrides.
void OnGatheringStateChanged(cricket::IceGatheringState new_state) override;
void OnCandidateGathered(const cricket::Candidate& candidate) override;
// Fills in |local_parameters_| with a random usernameFragment and a random
// password.
void GenerateLocalParameters();
bool IsClosed() const { return state_ == RTCIceTransportState::kClosed; }
bool RaiseExceptionIfClosed(ExceptionState& exception_state) const;
RTCIceTransportState state_ = RTCIceTransportState::kNew;
cricket::IceGatheringState gathering_state_ = cricket::kIceGatheringNew;
HeapVector<Member<RTCIceCandidate>> local_candidates_;
HeapVector<Member<RTCIceCandidate>> remote_candidates_;
RTCIceParameters local_parameters_;
base::Optional<RTCIceCandidatePair> selected_candidate_pair_;
// Handle to the WebRTC ICE transport. Created when this binding is
// constructed and deleted once network traffic should be stopped.
std::unique_ptr<IceTransportProxy> proxy_;
};
} // namespace blink
......
......@@ -28,11 +28,13 @@ enum RTCIceGatheringState {
// https://w3c.github.io/webrtc-pc/#rtcicetransport
[
ActiveScriptWrappable,
// Constructor from https://w3c.github.io/webrtc-ice/#rtcicetransport*
Constructor(),
ConstructorCallWith=ExecutionContext,
Exposed=Window,
RuntimeEnabled=RTCIceTransportExtension
] interface RTCIceTransport {
] interface RTCIceTransport : EventTarget {
// TODO(github.com/w3c/webrtc-ice/issues/4): role is non-null in the
// WebRTC-PC specification.
readonly attribute RTCIceRole? role;
......@@ -43,6 +45,13 @@ enum RTCIceGatheringState {
RTCIceCandidatePair? getSelectedCandidatePair();
RTCIceParameters? getLocalParameters();
RTCIceParameters? getRemoteParameters();
attribute EventHandler ongatheringstatechange;
// TODO(crbug.com/864871): Add events and extension methods.
// The following is defined in the WebRTC-ICE extension specification.
// https://w3c.github.io/webrtc-ice/#rtcicetransport*
[RaisesException] void gather(RTCIceGatherOptions options);
void stop();
attribute EventHandler onicecandidate;
// TODO(crbug.com/864871): Implement remaining events and extension methods.
};
......@@ -405,9 +405,24 @@ _CONFIG = [
'third_party/blink/renderer/bindings/modules/v8/serialization',
],
'allowed': [
'webrtc::.+',
'cricket::.*',
'rtc::.+',
'webrtc::.+',
]
},
{
'paths': [
'third_party/blink/renderer/modules/peerconnection/adapters/',
],
# The code in adapters/ wraps WebRTC APIs using STL/WebRTC types only.
# Thus, the restriction that objects should only be created and
# destroyed on the same thread can be relaxed since no Blink types (like
# AtomicString or HeapVector) are used cross thread. These Blink types
# are converted to the STL/WebRTC counterparts in the parent directory.
'allowed': [
'base::OnTaskRunnerDeleter',
'sigslot::.+',
],
}
]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment