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

Implement RTCIceTransport.onselectedcandidatepairchange

Bug: 864871
Change-Id: I710b18f8644be51d08b33b9852c00f4fbacec286
Reviewed-on: https://chromium-review.googlesource.com/1208961Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Reviewed-by: default avatarHarald Alvestrand <hta@chromium.org>
Commit-Queue: Steve Anton <steveanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595700}
parent f41f01a8
......@@ -15,12 +15,6 @@
// makeIceTransport
// makeGatherAndStartTwoIceTransports
function makeIceTransport(t) {
const iceTransport = new RTCIceTransport();
t.add_cleanup(() => iceTransport.stop());
return iceTransport;
}
test(() => {
const iceTransport = new RTCIceTransport();
}, 'RTCIceTransport constructor does not throw');
......@@ -260,4 +254,49 @@ promise_test(async t => {
]);
}, 'Two RTCIceTransports connect to each other');
promise_test(async t => {
async function waitForConnectedThenSelectedCandidatePairChange(t, transport,
transportName) {
const watcher = new EventWatcher(t, localTransport,
[ 'statechange', 'selectedcandidatepairchange' ]);
await watcher.wait_for('statechange');
assert_equals(transport.state, 'connected',
`${transportName} state should be 'connected'`);
await watcher.wait_for('selectedcandidatepairchange');
const selectedCandidatePair = transport.getSelectedCandidatePair();
assert_not_equals(selectedCandidatePair, null,
`${transportName} selected candidate pair should not be null once ` +
'the selectedcandidatepairchange event fires');
assert_true(
transport.getLocalCandidates().some(
({ candidate }) =>
candidate === selectedCandidatePair.local.candidate),
`${transportName} selected candidate pair local should be in the ` +
'list of local candidates');
assert_true(
transport.getRemoteCandidates().some(
({ candidate }) =>
candidate === selectedCandidatePair.remote.candidate),
`${transportName} selected candidate pair local should be in the ` +
'list of remote candidates');
}
const [ localTransport, remoteTransport ] =
makeGatherAndStartTwoIceTransports(t);
await Promise.all([
waitForConnectedThenSelectedCandidatePairChange(t, localTransport,
'local transport'),
waitForConnectedThenSelectedCandidatePairChange(t, remoteTransport,
'remote transport'),
]);
}, 'Selected candidate pair changes once the RTCIceTransports connect.');
promise_test(async t => {
const [ transport, ] = makeGatherAndStartTwoIceTransports(t);
const watcher = new EventWatcher(t, transport, 'selectedcandidatepairchange');
await watcher.wait_for('selectedcandidatepairchange');
transport.stop();
assert_equals(transport.getSelectedCandidatePair(), null);
}, 'getSelectedCandidatePair() returns null once the RTCIceTransport is ' +
'stopped.');
</script>
......@@ -338,7 +338,7 @@ PASS RTCIceTransport interface: operation getLocalParameters()
PASS RTCIceTransport interface: operation getRemoteParameters()
PASS RTCIceTransport interface: attribute onstatechange
PASS RTCIceTransport interface: attribute ongatheringstatechange
FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_true: The prototype object must have a property "onselectedcandidatepairchange" expected true got false
PASS RTCIceTransport interface: attribute onselectedcandidatepairchange
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"
FAIL RTCIceTransport interface: idlTestObjects.iceTransport must inherit property "role" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
......
......@@ -338,7 +338,7 @@ PASS RTCIceTransport interface: operation getLocalParameters()
PASS RTCIceTransport interface: operation getRemoteParameters()
PASS RTCIceTransport interface: attribute onstatechange
PASS RTCIceTransport interface: attribute ongatheringstatechange
FAIL RTCIceTransport interface: attribute onselectedcandidatepairchange assert_true: The prototype object must have a property "onselectedcandidatepairchange" expected true got false
PASS RTCIceTransport interface: attribute onselectedcandidatepairchange
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"
FAIL RTCIceTransport interface: idlTestObjects.iceTransport must inherit property "role" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
......
......@@ -5496,6 +5496,7 @@ interface RTCIceTransport : EventTarget
getter gatheringState
getter ongatheringstatechange
getter onicecandidate
getter onselectedcandidatepairchange
getter onstatechange
getter role
getter state
......@@ -5511,6 +5512,7 @@ interface RTCIceTransport : EventTarget
method stop
setter ongatheringstatechange
setter onicecandidate
setter onselectedcandidatepairchange
setter onstatechange
interface RTCPeerConnection : EventTarget
static method generateCertificate
......
......@@ -236,6 +236,7 @@
"seeked",
"seeking",
"select",
"selectedcandidatepairchange",
"selectionchange",
"selectstart",
"selectend",
......
......@@ -47,6 +47,12 @@ class IceTransportAdapter {
// Called asynchronously when the ICE connection state has changed.
virtual void OnStateChanged(cricket::IceTransportState new_state) {}
// Called asynchronously when the ICE agent selects a different candidate
// pair for the active connection.
virtual void OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) {}
};
virtual ~IceTransportAdapter() = default;
......
......@@ -106,6 +106,8 @@ IceTransportAdapterImpl::IceTransportAdapterImpl(
this, &IceTransportAdapterImpl::OnCandidateGathered);
p2p_transport_channel_->SignalStateChanged.connect(
this, &IceTransportAdapterImpl::OnStateChanged);
p2p_transport_channel_->SignalNetworkRouteChanged.connect(
this, &IceTransportAdapterImpl::OnNetworkRouteChanged);
// 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
......@@ -192,4 +194,21 @@ void IceTransportAdapterImpl::OnStateChanged(
delegate_->OnStateChanged(p2p_transport_channel_->GetState());
}
void IceTransportAdapterImpl::OnNetworkRouteChanged(
absl::optional<rtc::NetworkRoute> new_network_route) {
const cricket::CandidatePairInterface* selected_connection =
p2p_transport_channel_->selected_connection();
if (!selected_connection) {
// 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_connection->local_candidate(),
selected_connection->remote_candidate()));
}
} // namespace blink
......@@ -45,6 +45,8 @@ class IceTransportAdapterImpl final : public IceTransportAdapter,
void OnCandidateGathered(cricket::IceTransportInternal* transport,
const cricket::Candidate& candidate);
void OnStateChanged(cricket::IceTransportInternal* transport);
void OnNetworkRouteChanged(
absl::optional<rtc::NetworkRoute> new_network_route);
Delegate* const delegate_;
std::unique_ptr<cricket::PortAllocator> port_allocator_;
......
......@@ -108,4 +108,14 @@ void IceTransportHost::OnStateChanged(cricket::IceTransportState new_state) {
CrossThreadBind(&IceTransportProxy::OnStateChanged, proxy_, new_state));
}
void IceTransportHost::OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
PostCrossThreadTask(
*proxy_thread_, FROM_HERE,
CrossThreadBind(&IceTransportProxy::OnSelectedCandidatePairChanged,
proxy_, selected_candidate_pair));
}
} // namespace blink
......@@ -73,6 +73,9 @@ class IceTransportHost final : public IceTransportAdapter::Delegate {
void OnGatheringStateChanged(cricket::IceGatheringState new_state) override;
void OnCandidateGathered(const cricket::Candidate& candidate) override;
void OnStateChanged(cricket::IceTransportState new_state) override;
void OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) override;
const scoped_refptr<base::SingleThreadTaskRunner> proxy_thread_;
std::unique_ptr<IceTransportAdapter> transport_;
......
......@@ -140,4 +140,11 @@ void IceTransportProxy::OnStateChanged(cricket::IceTransportState new_state) {
delegate_->OnStateChanged(new_state);
}
void IceTransportProxy::OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
delegate_->OnSelectedCandidatePairChanged(selected_candidate_pair);
}
} // namespace blink
......@@ -50,6 +50,9 @@ class IceTransportProxy final {
}
virtual void OnCandidateGathered(const cricket::Candidate& candidate) {}
virtual void OnStateChanged(cricket::IceTransportState new_state) {}
virtual void OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) {}
};
// Construct a Proxy with the underlying ICE implementation running on the
......@@ -94,6 +97,9 @@ class IceTransportProxy final {
void OnGatheringStateChanged(cricket::IceGatheringState new_state);
void OnCandidateGathered(const cricket::Candidate& candidate);
void OnStateChanged(cricket::IceTransportState new_state);
void OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair);
const scoped_refptr<base::SingleThreadTaskRunner> proxy_thread_;
const scoped_refptr<base::SingleThreadTaskRunner> host_thread_;
......
......@@ -79,6 +79,13 @@ struct CrossThreadCopier<std::vector<rtc::scoped_refptr<rtc::RTCCertificate>>>
STATIC_ONLY(CrossThreadCopier);
};
template <>
struct CrossThreadCopier<std::pair<cricket::Candidate, cricket::Candidate>>
: public CrossThreadCopierPassThrough<
std::pair<cricket::Candidate, cricket::Candidate>> {
STATIC_ONLY(CrossThreadCopier);
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_PEERCONNECTION_ADAPTERS_WEB_RTC_CROSS_THREAD_COPIER_H_
......@@ -380,6 +380,7 @@ void RTCIceTransport::stop() {
// Stopping the consumer should cause it to disconnect.
DCHECK(!HasConsumer());
state_ = RTCIceTransportState::kClosed;
selected_candidate_pair_ = base::nullopt;
proxy_.reset();
}
......@@ -455,9 +456,25 @@ void RTCIceTransport::OnStateChanged(cricket::IceTransportState new_state) {
return;
}
state_ = local_new_state;
if (state_ == RTCIceTransportState::kFailed) {
selected_candidate_pair_ = base::nullopt;
}
DispatchEvent(*Event::Create(EventTypeNames::statechange));
}
void RTCIceTransport::OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) {
RTCIceCandidate* local =
ConvertToRtcIceCandidate(selected_candidate_pair.first);
RTCIceCandidate* remote =
ConvertToRtcIceCandidate(selected_candidate_pair.second);
selected_candidate_pair_ = RTCIceCandidatePair();
selected_candidate_pair_->setLocal(local);
selected_candidate_pair_->setRemote(remote);
DispatchEvent(*Event::Create(EventTypeNames::selectedcandidatepairchange));
}
bool RTCIceTransport::RaiseExceptionIfClosed(
ExceptionState& exception_state) const {
if (IsClosed()) {
......
......@@ -99,6 +99,7 @@ class MODULES_EXPORT RTCIceTransport final
ExceptionState& exception_state);
DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(gatheringstatechange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(selectedcandidatepairchange);
DEFINE_ATTRIBUTE_EVENT_LISTENER(icecandidate);
// EventTarget overrides.
......@@ -125,6 +126,9 @@ class MODULES_EXPORT RTCIceTransport final
void OnGatheringStateChanged(cricket::IceGatheringState new_state) override;
void OnCandidateGathered(const cricket::Candidate& candidate) override;
void OnStateChanged(cricket::IceTransportState new_state) override;
void OnSelectedCandidatePairChanged(
const std::pair<cricket::Candidate, cricket::Candidate>&
selected_candidate_pair) override;
// Fills in |local_parameters_| with a random usernameFragment and a random
// password.
......
......@@ -47,7 +47,7 @@ enum RTCIceGatheringState {
RTCIceParameters? getRemoteParameters();
attribute EventHandler onstatechange;
attribute EventHandler ongatheringstatechange;
// TODO(crbug.com/864871): Implement onselectedcandidatepairchange.
attribute EventHandler onselectedcandidatepairchange;
// The following is defined in the WebRTC-ICE extension specification.
// https://w3c.github.io/webrtc-ice/#rtcicetransport*
......
......@@ -442,6 +442,7 @@ _CONFIG = [
# AtomicString or HeapVector) are used cross thread. These Blink types
# are converted to the STL/WebRTC counterparts in the parent directory.
'allowed': [
'absl::.+',
'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