diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index 5655a792c967..dd6029f67d25 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -341,6 +341,10 @@ function RTCPeerConnection() { this._localType = null; this._remoteType = null; + // http://rtcweb-wg.github.io/jsep/#rfc.section.4.1.9 + // canTrickle == null means unknown; when a remote description is received it + // is set to true or false based on the presence of the "trickle" ice-option + this._canTrickle = null; // States this._iceGatheringState = this._iceConnectionState = "new"; @@ -919,7 +923,7 @@ RTCPeerConnection.prototype = { this._onSetRemoteDescriptionSuccess = resolve; this._onSetRemoteDescriptionFailure = reject; this._impl.setRemoteDescription(type, desc.sdp); - })); + })).then(() => { this._updateCanTrickle(); }); if (desc.type === "rollback") { return setRem; @@ -947,9 +951,37 @@ RTCPeerConnection.prototype = { ); }, - updateIce: function(config) { - throw new this._win.DOMException("updateIce not yet implemented", - "NotSupportedError"); + get canTrickleIceCandidates() { + return this._canTrickle; + }, + + _updateCanTrickle: function() { + let containsTrickle = section => { + let lines = section.toLowerCase().split(/(?:\r\n?|\n)/); + return lines.some(line => { + let prefix = "a=ice-options:"; + if (line.substring(0, prefix.length) !== prefix) { + return false; + } + let tokens = line.substring(prefix.length).split(" "); + return tokens.some(x => x === "trickle"); + }); + }; + + let desc = null; + try { + // The getter for remoteDescription can throw if the pc is closed. + desc = this.remoteDescription; + } catch (e) {} + if (!desc) { + this._canTrickle = null; + return; + } + + let sections = desc.sdp.split(/(?:\r\n?|\n)m=/); + let topSection = sections.shift(); + this._canTrickle = + containsTrickle(topSection) || sections.every(containsTrickle); }, addIceCandidate: function(c, onSuccess, onError) { diff --git a/dom/media/tests/mochitest/nonTrickleIce.js b/dom/media/tests/mochitest/nonTrickleIce.js index ce59b89b54c6..2733b64947b3 100644 --- a/dom/media/tests/mochitest/nonTrickleIce.js +++ b/dom/media/tests/mochitest/nonTrickleIce.js @@ -2,6 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +function removeTrickleOption(desc) { + var sdp = desc.sdp.replace(/\r\na=ice-options:trickle\r\n/, "\r\n"); + return new mozRTCSessionDescription({ type: desc.type, sdp: sdp }); +} + function makeOffererNonTrickle(chain) { chain.replace('PC_LOCAL_SETUP_ICE_HANDLER', [ function PC_LOCAL_SETUP_NOTRICKLE_ICE_HANDLER(test) { @@ -14,7 +19,7 @@ function makeOffererNonTrickle(chain) { chain.replace('PC_REMOTE_GET_OFFER', [ function PC_REMOTE_GET_FULL_OFFER(test) { return test.pcLocal.endOfTrickleIce.then(() => { - test._local_offer = test.pcLocal.localDescription; + test._local_offer = removeTrickleOption(test.pcLocal.localDescription); test._offer_constraints = test.pcLocal.constraints; test._offer_options = test.pcLocal.offerOptions; }); @@ -24,11 +29,14 @@ function makeOffererNonTrickle(chain) { function PC_REMOTE_REQUIRE_REMOTE_SDP_CANDIDATES(test) { info("test.pcLocal.localDescription.sdp: " + JSON.stringify(test.pcLocal.localDescription.sdp)); info("test._local_offer.sdp" + JSON.stringify(test._local_offer.sdp)); + is(test.pcRemote._pc.canTrickleIceCandidates, false, + "Remote thinks that trickle isn't supported"); ok(!test.localRequiresTrickleIce, "Local does NOT require trickle"); ok(test._local_offer.sdp.includes("a=candidate"), "offer has ICE candidates") ok(test._local_offer.sdp.includes("a=end-of-candidates"), "offer has end-of-candidates"); } ]); + chain.remove('PC_REMOTE_CHECK_CAN_TRICKLE_SYNC'); } function makeAnswererNonTrickle(chain) { @@ -43,7 +51,7 @@ function makeAnswererNonTrickle(chain) { chain.replace('PC_LOCAL_GET_ANSWER', [ function PC_LOCAL_GET_FULL_ANSWER(test) { return test.pcRemote.endOfTrickleIce.then(() => { - test._remote_answer = test.pcRemote.localDescription; + test._remote_answer = removeTrickleOption(test.pcRemote.localDescription); test._answer_constraints = test.pcRemote.constraints; }); } @@ -52,9 +60,12 @@ function makeAnswererNonTrickle(chain) { function PC_LOCAL_REQUIRE_REMOTE_SDP_CANDIDATES(test) { info("test.pcRemote.localDescription.sdp: " + JSON.stringify(test.pcRemote.localDescription.sdp)); info("test._remote_answer.sdp" + JSON.stringify(test._remote_answer.sdp)); + is(test.pcLocal._pc.canTrickleIceCandidates, false, + "Local thinks that trickle isn't supported"); ok(!test.remoteRequiresTrickleIce, "Remote does NOT require trickle"); ok(test._remote_answer.sdp.includes("a=candidate"), "answer has ICE candidates") ok(test._remote_answer.sdp.includes("a=end-of-candidates"), "answer has end-of-candidates"); } ]); + chain.remove('PC_LOCAL_CHECK_CAN_TRICKLE_SYNC'); } diff --git a/dom/media/tests/mochitest/templates.js b/dom/media/tests/mochitest/templates.js index 5b9d1377d343..670bf3ee951a 100644 --- a/dom/media/tests/mochitest/templates.js +++ b/dom/media/tests/mochitest/templates.js @@ -193,6 +193,15 @@ var commandsPeerConnectionInitial = [ "Initial remote ICE connection state is 'new'"); }, + function PC_LOCAL_CHECK_INITIAL_CAN_TRICKLE_SYNC(test) { + is(test.pcLocal._pc.canTrickleIceCandidates, null, + "Local trickle status should start out unknown"); + }, + + function PC_REMOTE_CHECK_INITIAL_CAN_TRICKLE_SYNC(test) { + is(test.pcRemote._pc.canTrickleIceCandidates, null, + "Remote trickle status should start out unknown"); + }, ]; var commandsGetUserMedia = [ @@ -305,6 +314,11 @@ var commandsPeerConnectionOfferAnswer = [ }); }, + function PC_REMOTE_CHECK_CAN_TRICKLE_SYNC(test) { + is(test.pcRemote._pc.canTrickleIceCandidates, true, + "Remote thinks that local can trickle"); + }, + function PC_LOCAL_SANE_LOCAL_SDP(test) { test.pcLocal.localRequiresTrickleIce = sdputils.verifySdp(test._local_offer, "offer", @@ -376,6 +390,11 @@ var commandsPeerConnectionOfferAnswer = [ test.testOptions); }, + function PC_LOCAL_CHECK_CAN_TRICKLE_SYNC(test) { + is(test.pcLocal._pc.canTrickleIceCandidates, true, + "Local thinks that remote can trickle"); + }, + function PC_LOCAL_WAIT_FOR_ICE_CONNECTED(test) { return waitForIceConnected(test, test.pcLocal); }, diff --git a/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html b/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html index 091a28de93c1..0254ebc656fb 100644 --- a/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html +++ b/dom/media/tests/mochitest/test_peerConnection_remoteRollback.html @@ -6,41 +6,45 @@
 
 
- diff --git a/dom/webidl/RTCPeerConnection.webidl b/dom/webidl/RTCPeerConnection.webidl index 923b38a215d2..1fbd01c801c1 100644 --- a/dom/webidl/RTCPeerConnection.webidl +++ b/dom/webidl/RTCPeerConnection.webidl @@ -4,7 +4,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCPeerConnection + * http://w3c.github.io/webrtc-pc/#interface-definition */ callback RTCSessionDescriptionCallback = void (RTCSessionDescription sdp); @@ -103,8 +103,8 @@ interface RTCPeerConnection : EventTarget { readonly attribute RTCSessionDescription? localDescription; readonly attribute RTCSessionDescription? remoteDescription; readonly attribute RTCSignalingState signalingState; - void updateIce (optional RTCConfiguration configuration); Promise addIceCandidate (RTCIceCandidate candidate); + readonly attribute boolean? canTrickleIceCandidates; readonly attribute RTCIceGatheringState iceGatheringState; readonly attribute RTCIceConnectionState iceConnectionState; [Pref="media.peerconnection.identity.enabled"] diff --git a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini b/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini index d9bfc0c33735..c4d43682899b 100644 --- a/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini +++ b/testing/web-platform/meta/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html.ini @@ -13,7 +13,7 @@ expected: FAIL [RTCPeerConnection interface: attribute canTrickleIceCandidates] - expected: FAIL + expected: PASS [RTCPeerConnection interface: attribute onicegatheringstatechange] expected: FAIL @@ -109,7 +109,7 @@ expected: FAIL [RTCPeerConnection interface: pc must inherit property "canTrickleIceCandidates" with the proper type (14)] - expected: FAIL + expected: PASS [RTCPeerConnection interface: pc must inherit property "setConfiguration" with the proper type (16)] expected: FAIL @@ -172,7 +172,7 @@ expected: FAIL [RTCPeerConnection interface: attribute canTrickleIceCandidates] - expected: FAIL + expected: PASS [RTCPeerConnection interface: attribute onicegatheringstatechange] expected: FAIL @@ -244,7 +244,7 @@ expected: FAIL [RTCPeerConnection interface: pc must inherit property "canTrickleIceCandidates" with the proper type (11)] - expected: FAIL + expected: PASS [RTCPeerConnection interface: pc must inherit property "onnegotiationneeded" with the proper type (14)] expected: FAIL