From 2de8192c1e2560b521316364b0a89d012a843669 Mon Sep 17 00:00:00 2001 From: "Nils Ohlmeier [:drno]" Date: Mon, 24 Aug 2015 14:49:41 -0700 Subject: [PATCH] Bug 1167443 - Fix verification of end-of-candidates in mochitests. r=mt --- dom/media/tests/mochitest/mochitest.ini | 7 + dom/media/tests/mochitest/pc.js | 212 +++++++----------- dom/media/tests/mochitest/sdpUtils.js | 111 +++++++++ dom/media/tests/mochitest/templates.js | 122 +++++----- ...t_dataChannel_basicAudioVideoNoBundle.html | 14 +- ...peerConnection_addDataChannelNoBundle.html | 5 +- ...nnection_addSecondAudioStreamNoBundle.html | 5 +- ...nnection_addSecondVideoStreamNoBundle.html | 5 +- ...t_peerConnection_basicAudioRequireEOC.html | 35 +++ ...eerConnection_basicAudioVideoNoBundle.html | 5 +- ...tion_basicAudioVideoNoBundleNoRtcpMux.html | 39 ++++ ...erConnection_basicAudioVideoNoRtcpMux.html | 38 ++++ 12 files changed, 377 insertions(+), 221 deletions(-) create mode 100644 dom/media/tests/mochitest/sdpUtils.js create mode 100644 dom/media/tests/mochitest/test_peerConnection_basicAudioRequireEOC.html create mode 100644 dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html create mode 100644 dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoRtcpMux.html diff --git a/dom/media/tests/mochitest/mochitest.ini b/dom/media/tests/mochitest/mochitest.ini index af3b11fa42d..0a1ea4e2a7e 100644 --- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -13,6 +13,7 @@ support-files = NetworkPreparationChromeScript.js blacksilence.js turnConfig.js + sdpUtils.js [test_dataChannel_basicAudio.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' # Bug 962984 for debug, bug 963244 for opt @@ -62,12 +63,18 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 1021776, too --ing [test_peerConnection_addIceCandidate.html] [test_peerConnection_basicAudio.html] skip-if = toolkit == 'gonk' # B2G emulator is too slow to handle a two-way audio call reliably +[test_peerConnection_basicAudioRequireEOC.html] +skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g (Bug 1059867) [test_peerConnection_basicAudioVideo.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator) [test_peerConnection_basicAudioVideoCombined.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator) [test_peerConnection_basicAudioVideoNoBundle.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g(Bug 960442, video support for WebRTC is disabled on b2g), android(Bug 1189784, timeouts on 4.3 emulator) +[test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html] +skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) +[test_peerConnection_basicAudioVideoNoRtcpMux.html] +skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) [test_peerConnection_basicVideo.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) [test_peerConnection_basicScreenshare.html] diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index 163506f0974..b6c7c9456b3 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -28,19 +28,6 @@ const signalingStateTransitions = { "closed": [] } -// Also remove mode 0 if it's offered -// Note, we don't bother removing the fmtp lines, which makes a good test -// for some SDP parsing issues. -function removeVP8(sdp) { - var updated_sdp = sdp.replace("a=rtpmap:120 VP8/90000\r\n",""); - updated_sdp = updated_sdp.replace("RTP/SAVPF 120 126 97\r\n","RTP/SAVPF 126 97\r\n"); - updated_sdp = updated_sdp.replace("RTP/SAVPF 120 126\r\n","RTP/SAVPF 126\r\n"); - updated_sdp = updated_sdp.replace("a=rtcp-fb:120 nack\r\n",""); - updated_sdp = updated_sdp.replace("a=rtcp-fb:120 nack pli\r\n",""); - updated_sdp = updated_sdp.replace("a=rtcp-fb:120 ccm fir\r\n",""); - return updated_sdp; -} - var makeDefaultCommands = () => { return [].concat(commandsPeerConnectionInitial, commandsGetUserMedia, @@ -72,6 +59,10 @@ function PeerConnectionTest(options) { options.is_local = "is_local" in options ? options.is_local : true; options.is_remote = "is_remote" in options ? options.is_remote : true; + options.h264 = "h264" in options ? options.h264 : false; + options.bundle = "bundle" in options ? options.bundle : true; + options.rtcpmux = "rtcpmux" in options ? options.rtcpmux : true; + if (typeof turnServers !== "undefined") { if ((!options.turn_disabled_local) && (turnServers.local)) { if (!options.hasOwnProperty("config_local")) { @@ -91,26 +82,24 @@ function PeerConnectionTest(options) { } } - if (options.is_local) - this.pcLocal = new PeerConnectionWrapper('pcLocal', options.config_local, options.h264); - else + if (options.is_local) { + this.pcLocal = new PeerConnectionWrapper('pcLocal', options.config_local); + } else { this.pcLocal = null; + } - if (options.is_remote) - this.pcRemote = new PeerConnectionWrapper('pcRemote', options.config_remote || options.config_local, options.h264); - else + if (options.is_remote) { + this.pcRemote = new PeerConnectionWrapper('pcRemote', options.config_remote || options.config_local); + } else { this.pcRemote = null; + } - this.steeplechase = this.pcLocal === null || this.pcRemote === null; + options.steeplechase = !options.is_local || !options.is_remote; // Create command chain instance and assign default commands this.chain = new CommandChain(this, options.commands); - if (!options.is_local) { - this.chain.filterOut(/^PC_LOCAL/); - } - if (!options.is_remote) { - this.chain.filterOut(/^PC_REMOTE/); - } + + this.testOptions = options; } /** TODO: consider removing this dependency on timeouts */ @@ -332,6 +321,14 @@ function(peer, desc, stateExpected) { peer.setLocalDescDate = new Date(); }); + peer.endOfTrickleSdp = peer.endOfTrickleIce.then(() => { + if (this.testOptions.steeplechase) { + send_message({"type": "end_of_trickle_ice"}); + } + return peer._pc.localDescription; + }) + .catch(e => ok(false, "Sending EOC message failed: " + e)); + return Promise.all([eventFired, stateChanged]); }; @@ -396,10 +393,41 @@ function(peer, desc, stateExpected) { return Promise.all([eventFired, stateChanged]); }; +/** + * Adds and removes steps to/from the execution chain based on the configured + * testOptions. + */ +PeerConnectionTest.prototype.updateChainSteps = function() { + if (this.testOptions.h264) { + this.chain.insertAfterEach( + 'PC_LOCAL_CREATE_OFFER', + [PC_LOCAL_REMOVE_VP8_FROM_OFFER]); + } + if (!this.testOptions.bundle) { + this.chain.insertAfterEach( + 'PC_LOCAL_CREATE_OFFER', + [PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER]); + } + if (!this.testOptions.rtcpmux) { + this.chain.insertAfterEach( + 'PC_LOCAL_CREATE_OFFER', + [PC_LOCAL_REMOVE_RTCPMUX_FROM_OFFER]); + } + if (!this.testOptions.is_local) { + this.chain.filterOut(/^PC_LOCAL/); + } + if (!this.testOptions.is_remote) { + this.chain.filterOut(/^PC_REMOTE/); + } +}; + /** * Start running the tests as assigned to the command chain. */ PeerConnectionTest.prototype.run = function() { + /* We have to modify the chain here to allow tests which modify the default + * test chain instantiating a PeerConnectionTest() */ + this.updateChainSteps(); return this.chain.execute() .then(() => this.close()) .then(() => { @@ -651,7 +679,7 @@ DataChannelWrapper.prototype = { * @param {object} configuration * Configuration for the peer connection instance */ -function PeerConnectionWrapper(label, configuration, h264) { +function PeerConnectionWrapper(label, configuration) { this.configuration = configuration; if (configuration && configuration.label_suffix) { label = label + "_" + configuration.label_suffix; @@ -680,8 +708,6 @@ function PeerConnectionWrapper(label, configuration, h264) { this.iceCheckingRestartExpected = false; - this.h264 = typeof h264 !== "undefined" ? true : false; - info("Creating " + this); this._pc = new mozRTCPeerConnection(this.configuration); @@ -918,10 +944,6 @@ PeerConnectionWrapper.prototype = { info("Got offer: " + JSON.stringify(offer)); // note: this might get updated through ICE gathering this._latest_offer = offer; - if (this.h264) { - isnot(offer.sdp.search("H264/90000"), -1, "H.264 should be present in the SDP offer"); - offer.sdp = removeVP8(offer.sdp); - } return offer; }); }, @@ -1215,18 +1237,16 @@ PeerConnectionWrapper.prototype = { this.endOfTrickleIce = new Promise(r => resolveEndOfTrickle = r); this.holdIceCandidates = new Promise(r => this.releaseIceCandidates = r); - this.endOfTrickleIce.then(() => { - this._pc.onicecandidate = () => - ok(false, this.label + " received ICE candidate after end of trickle"); - var localSdp = this._pc.getLocalDescription(); - ok(localSdp.includes("a=end-of-candidates")); - ok(localSdp.includes("a=rtcp:")); - ok(!localSdp.includes("c=IN IP4 0.0.0.0")); - }); - this._pc.onicecandidate = anEvent => { if (!anEvent.candidate) { + this._pc.onicecandidate = () => + ok(false, this.label + " received ICE candidate after end of trickle"); info(this.label + ": received end of trickle ICE event"); + /* Bug 1193731. Accroding to WebRTC spec 4.3.1 the ICE Agent first sets + * the gathering state to completed (step 3.) before sending out the + * null newCandidate in step 4. */ + todo(this._pc.iceGatheringState === 'completed', + "ICE gathering state has reached completed"); resolveEndOfTrickle(this.label); return; } @@ -1241,19 +1261,6 @@ PeerConnectionWrapper.prototype = { }; }, - /** - * Counts the amount of audio tracks in a given media constraint. - * - * @param constraints - * The contraint to be examined. - */ - countTracksInConstraint : function(type, constraints) { - if (!Array.isArray(constraints)) { - return 0; - } - return constraints.reduce((sum, c) => sum + (c[type] ? 1 : 0), 0); - }, - checkLocalMediaTracks : function() { var observed = {}; info(this + " Checking local tracks " + JSON.stringify(this.expectedLocalTrackInfoById)); @@ -1302,66 +1309,6 @@ PeerConnectionWrapper.prototype = { "remote"); }, - verifySdp: function(desc, expectedType, offerConstraintsList, offerOptions, isLocal) { - info("Examining this SessionDescription: " + JSON.stringify(desc)); - info("offerConstraintsList: " + JSON.stringify(offerConstraintsList)); - info("offerOptions: " + JSON.stringify(offerOptions)); - ok(desc, "SessionDescription is not null"); - is(desc.type, expectedType, "SessionDescription type is " + expectedType); - ok(desc.sdp.length > 10, "SessionDescription body length is plausible"); - ok(desc.sdp.includes("a=ice-ufrag"), "ICE username is present in SDP"); - ok(desc.sdp.includes("a=ice-pwd"), "ICE password is present in SDP"); - ok(desc.sdp.includes("a=fingerprint"), "ICE fingerprint is present in SDP"); - //TODO: update this for loopback support bug 1027350 - ok(!desc.sdp.includes(LOOPBACK_ADDR), "loopback interface is absent from SDP"); - var requiresTrickleIce = !desc.sdp.includes("a=candidate"); - if (requiresTrickleIce) { - info("at least one ICE candidate is present in SDP"); - } else { - info("No ICE candidate in SDP -> requiring trickle ICE"); - } - if (isLocal) { - this.localRequiresTrickleIce = requiresTrickleIce; - } else { - this.remoteRequiresTrickleIce = requiresTrickleIce; - } - - //TODO: how can we check for absence/presence of m=application? - - var audioTracks = - this.countTracksInConstraint('audio', offerConstraintsList) || - ((offerOptions && offerOptions.offerToReceiveAudio) ? 1 : 0); - - info("expected audio tracks: " + audioTracks); - if (audioTracks == 0) { - ok(!desc.sdp.includes("m=audio"), "audio m-line is absent from SDP"); - } else { - ok(desc.sdp.includes("m=audio"), "audio m-line is present in SDP"); - ok(desc.sdp.includes("a=rtpmap:109 opus/48000/2"), "OPUS codec is present in SDP"); - //TODO: ideally the rtcp-mux should be for the m=audio, and not just - // anywhere in the SDP (JS SDP parser bug 1045429) - ok(desc.sdp.includes("a=rtcp-mux"), "RTCP Mux is offered in SDP"); - } - - var videoTracks = - this.countTracksInConstraint('video', offerConstraintsList) || - ((offerOptions && offerOptions.offerToReceiveVideo) ? 1 : 0); - - info("expected video tracks: " + videoTracks); - if (videoTracks == 0) { - ok(!desc.sdp.includes("m=video"), "video m-line is absent from SDP"); - } else { - ok(desc.sdp.includes("m=video"), "video m-line is present in SDP"); - if (this.h264) { - ok(desc.sdp.includes("a=rtpmap:126 H264/90000"), "H.264 codec is present in SDP"); - } else { - ok(desc.sdp.includes("a=rtpmap:120 VP8/90000"), "VP8 codec is present in SDP"); - } - ok(desc.sdp.includes("a=rtcp-mux"), "RTCP Mux is offered in SDP"); - } - - }, - /** * Check that media flow is present on the given media element by waiting for * it to reach ready state HAVE_ENOUGH_DATA and progress time further than @@ -1691,11 +1638,11 @@ PeerConnectionWrapper.prototype = { * The stats to check for ICE candidate pairs * @param {object} counters * The counters for media and data tracks based on constraints - * @param {object} answer - * The SDP answer to check for SDP bundle support + * @param {object} testOptions + * The test options object from the PeerConnectionTest */ checkStatsIceConnections : function(stats, - offerConstraintsList, offerOptions, answer) { + offerConstraintsList, offerOptions, testOptions) { var numIceConnections = 0; Object.keys(stats).forEach(key => { if ((stats[key].type === "candidatepair") && stats[key].selected) { @@ -1704,24 +1651,34 @@ PeerConnectionWrapper.prototype = { }); info("ICE connections according to stats: " + numIceConnections); isnot(numIceConnections, 0, "Number of ICE connections according to stats is not zero"); - if (answer.sdp.includes('a=group:BUNDLE')) { - is(numIceConnections, 1, "stats reports exactly 1 ICE connection"); + if (testOptions.bundle) { + if (testOptions.rtcpmux) { + is(numIceConnections, 1, "stats reports exactly 1 ICE connection"); + } else { + is(numIceConnections, 2, "stats report exactly 2 ICE connections for media and RTCP"); + } } else { // This code assumes that no media sections have been rejected due to // codec mismatch or other unrecoverable negotiation failures. var numAudioTracks = - this.countTracksInConstraint('audio', offerConstraintsList) || + sdputils.countTracksInConstraint('audio', offerConstraintsList) || ((offerOptions && offerOptions.offerToReceiveAudio) ? 1 : 0); var numVideoTracks = - this.countTracksInConstraint('video', offerConstraintsList) || + sdputils.countTracksInConstraint('video', offerConstraintsList) || ((offerOptions && offerOptions.offerToReceiveVideo) ? 1 : 0); - var numDataTracks = this.dataChannels.length; + var numExpectedTransports = numAudioTracks + numVideoTracks; + if (!testOptions.rtcpmux) { + numExpectedTransports *= 2; + } - var numAudioVideoDataTracks = numAudioTracks + numVideoTracks + numDataTracks; - info("expected audio + video + data tracks: " + numAudioVideoDataTracks); - is(numAudioVideoDataTracks, numIceConnections, "stats ICE connections matches expected A/V tracks"); + if (this.dataChannels.length) { + ++numExpectedTransports; + } + + info("expected audio + video + data transports: " + numExpectedTransports); + is(numIceConnections, numExpectedTransports, "stats ICE connections matches expected A/V transports"); } }, @@ -1789,7 +1746,8 @@ var scriptsReady = Promise.all([ "templates.js", "turnConfig.js", "dataChannel.js", - "network.js" + "network.js", + "sdpUtils.js" ].map(script => { var el = document.createElement("script"); if (typeof scriptRelativePath === 'string' && script.charAt(0) !== '/') { diff --git a/dom/media/tests/mochitest/sdpUtils.js b/dom/media/tests/mochitest/sdpUtils.js new file mode 100644 index 00000000000..218127e6566 --- /dev/null +++ b/dom/media/tests/mochitest/sdpUtils.js @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +var sdputils = { + +checkSdpAfterEndOfTrickle: function(sdp, testOptions, label) { + info("EOC-SDP: " + JSON.stringify(sdp)); + + ok(sdp.sdp.includes("a=end-of-candidates"), label + ": SDP contains end-of-candidates"); + ok(!sdp.sdp.includes("c=IN IP4 0.0.0.0"), label + ": SDP contains non-zero IP c line"); + + if (testOptions.rtcpmux) { + ok(sdp.sdp.includes("a=rtcp-mux"), label + ": SDP contains rtcp-mux"); + } else { + ok(sdp.sdp.includes("a=rtcp:"), label + ": SDP contains rtcp port"); + } +}, + +// Also remove mode 0 if it's offered +// Note, we don't bother removing the fmtp lines, which makes a good test +// for some SDP parsing issues. +removeVP8: function(sdp) { + var updated_sdp = sdp.replace("a=rtpmap:120 VP8/90000\r\n",""); + updated_sdp = updated_sdp.replace("RTP/SAVPF 120 126 97\r\n","RTP/SAVPF 126 97\r\n"); + updated_sdp = updated_sdp.replace("RTP/SAVPF 120 126\r\n","RTP/SAVPF 126\r\n"); + updated_sdp = updated_sdp.replace("a=rtcp-fb:120 nack\r\n",""); + updated_sdp = updated_sdp.replace("a=rtcp-fb:120 nack pli\r\n",""); + updated_sdp = updated_sdp.replace("a=rtcp-fb:120 ccm fir\r\n",""); + return updated_sdp; +}, + +removeRtcpMux: function(sdp) { + return sdp.replace(/a=rtcp-mux\r\n/g,""); +}, + +removeBundle: function(sdp) { + return sdp.replace(/a=group:BUNDLE .*\r\n/g, ""); +}, + +verifySdp: function(desc, expectedType, offerConstraintsList, offerOptions, + testOptions) { + info("Examining this SessionDescription: " + JSON.stringify(desc)); + info("offerConstraintsList: " + JSON.stringify(offerConstraintsList)); + info("offerOptions: " + JSON.stringify(offerOptions)); + ok(desc, "SessionDescription is not null"); + is(desc.type, expectedType, "SessionDescription type is " + expectedType); + ok(desc.sdp.length > 10, "SessionDescription body length is plausible"); + ok(desc.sdp.includes("a=ice-ufrag"), "ICE username is present in SDP"); + ok(desc.sdp.includes("a=ice-pwd"), "ICE password is present in SDP"); + ok(desc.sdp.includes("a=fingerprint"), "ICE fingerprint is present in SDP"); + //TODO: update this for loopback support bug 1027350 + ok(!desc.sdp.includes(LOOPBACK_ADDR), "loopback interface is absent from SDP"); + var requiresTrickleIce = !desc.sdp.includes("a=candidate"); + if (requiresTrickleIce) { + info("at least one ICE candidate is present in SDP"); + } else { + info("No ICE candidate in SDP -> requiring trickle ICE"); + } + + //TODO: how can we check for absence/presence of m=application? + + var audioTracks = + sdputils.countTracksInConstraint('audio', offerConstraintsList) || + ((offerOptions && offerOptions.offerToReceiveAudio) ? 1 : 0); + + info("expected audio tracks: " + audioTracks); + if (audioTracks == 0) { + ok(!desc.sdp.includes("m=audio"), "audio m-line is absent from SDP"); + } else { + ok(desc.sdp.includes("m=audio"), "audio m-line is present in SDP"); + ok(desc.sdp.includes("a=rtpmap:109 opus/48000/2"), "OPUS codec is present in SDP"); + //TODO: ideally the rtcp-mux should be for the m=audio, and not just + // anywhere in the SDP (JS SDP parser bug 1045429) + is(testOptions.rtcpmux, desc.sdp.includes("a=rtcp-mux"), "RTCP Mux is offered in SDP"); + } + + var videoTracks = + sdputils.countTracksInConstraint('video', offerConstraintsList) || + ((offerOptions && offerOptions.offerToReceiveVideo) ? 1 : 0); + + info("expected video tracks: " + videoTracks); + if (videoTracks == 0) { + ok(!desc.sdp.includes("m=video"), "video m-line is absent from SDP"); + } else { + ok(desc.sdp.includes("m=video"), "video m-line is present in SDP"); + if (testOptions.h264) { + ok(desc.sdp.includes("a=rtpmap:126 H264/90000"), "H.264 codec is present in SDP"); + } else { + ok(desc.sdp.includes("a=rtpmap:120 VP8/90000"), "VP8 codec is present in SDP"); + } + is(testOptions.rtcpmux, desc.sdp.includes("a=rtcp-mux"), "RTCP Mux is offered in SDP"); + } + + return requiresTrickleIce; +}, + +/** + * Counts the amount of audio tracks in a given media constraint. + * + * @param constraints + * The contraint to be examined. + */ +countTracksInConstraint: function(type, constraints) { + if (!Array.isArray(constraints)) { + return 0; + } + return constraints.reduce((sum, c) => sum + (c[type] ? 1 : 0), 0); +}, + +}; diff --git a/dom/media/tests/mochitest/templates.js b/dom/media/tests/mochitest/templates.js index 2a2ea7e2782..6a5dc7dbfda 100644 --- a/dom/media/tests/mochitest/templates.js +++ b/dom/media/tests/mochitest/templates.js @@ -208,20 +208,10 @@ var commandsGetUserMedia = [ var commandsPeerConnectionOfferAnswer = [ function PC_LOCAL_SETUP_ICE_HANDLER(test) { test.pcLocal.setupIceCandidateHandler(test); - if (test.steeplechase) { - test.pcLocal.endOfTrickleIce.then(() => { - send_message({"type": "end_of_trickle_ice"}); - }); - } }, function PC_REMOTE_SETUP_ICE_HANDLER(test) { test.pcRemote.setupIceCandidateHandler(test); - if (test.steeplechase) { - test.pcRemote.endOfTrickleIce.then(() => { - send_message({"type": "end_of_trickle_ice"}); - }); - } }, function PC_LOCAL_STEEPLECHASE_SIGNAL_EXPECTED_LOCAL_TRACKS(test) { @@ -316,15 +306,17 @@ var commandsPeerConnectionOfferAnswer = [ }, function PC_LOCAL_SANE_LOCAL_SDP(test) { - test.pcLocal.verifySdp(test._local_offer, "offer", - test._offer_constraints, test._offer_options, - true); + test.pcLocal.localRequiresTrickleIce = + sdputils.verifySdp(test._local_offer, "offer", + test._offer_constraints, test._offer_options, + test.testOptions); }, function PC_REMOTE_SANE_REMOTE_SDP(test) { - test.pcRemote.verifySdp(test._local_offer, "offer", - test._offer_constraints, test._offer_options, - false); + test.pcRemote.remoteRequiresTrickleIce = + sdputils.verifySdp(test._local_offer, "offer", + test._offer_constraints, test._offer_options, + test.testOptions); }, function PC_REMOTE_CREATE_ANSWER(test) { @@ -342,46 +334,6 @@ var commandsPeerConnectionOfferAnswer = [ }); }, - function PC_REMOTE_CHECK_FOR_DUPLICATED_PORTS_IN_SDP(test) { - var re = /a=candidate.* (UDP|TCP) [\d]+ ([\d\.]+) ([\d]+) typ host/g; - - var _sdpCandidatesIntoArray = sdp => { - var regexArray = []; - var resultArray = []; - while ((regexArray = re.exec(sdp)) !== null) { - info("regexArray: " + regexArray); - if ((regexArray[1] === "TCP") && (regexArray[3] === "9")) { - // As both sides can advertise TCP active connection on port 9 lets - // ignore them all together - info("Ignoring TCP candidate on port 9"); - continue; - } - var triple = regexArray[1] + ":" + regexArray[2] + ":" + regexArray[3]; - info("triple: " + triple); - if (resultArray.indexOf(triple) !== -1) { - dump("SDP: " + sdp.replace(/[\r]/g, '') + "\n"); - ok(false, "This Transport:IP:Port " + triple + " appears twice in the SDP above!"); - } - resultArray.push(triple); - } - return resultArray; - }; - - var offerTriples = _sdpCandidatesIntoArray(test._local_offer.sdp); - info("Offer ICE host candidates: " + JSON.stringify(offerTriples)); - - var answerTriples = _sdpCandidatesIntoArray(test.originalAnswer.sdp); - info("Answer ICE host candidates: " + JSON.stringify(answerTriples)); - - offerTriples.forEach(o => { - if (answerTriples.indexOf(o) !== -1) { - dump("SDP offer: " + test._local_offer.sdp.replace(/[\r]/g, '') + "\n"); - dump("SDP answer: " + test.originalAnswer.sdp.replace(/[\r]/g, '') + "\n"); - ok(false, "This IP:Port " + o + " appears in SDP offer and answer!"); - } - }); - }, - function PC_REMOTE_SET_LOCAL_DESCRIPTION(test) { return test.setLocalDescription(test.pcRemote, test.originalAnswer, STABLE) .then(() => { @@ -412,14 +364,16 @@ var commandsPeerConnectionOfferAnswer = [ }); }, function PC_REMOTE_SANE_LOCAL_SDP(test) { - test.pcRemote.verifySdp(test._remote_answer, "answer", - test._offer_constraints, test._offer_options, - true); + test.pcRemote.localRequiresTrickleIce = + sdputils.verifySdp(test._remote_answer, "answer", + test._offer_constraints, test._offer_options, + test.testOptions); }, function PC_LOCAL_SANE_REMOTE_SDP(test) { - test.pcLocal.verifySdp(test._remote_answer, "answer", - test._offer_constraints, test._offer_options, - false); + test.pcLocal.remoteRequiresTrickleIce = + sdputils.verifySdp(test._remote_answer, "answer", + test._offer_constraints, test._offer_options, + test.testOptions); }, function PC_LOCAL_WAIT_FOR_ICE_CONNECTED(test) { @@ -483,7 +437,7 @@ var commandsPeerConnectionOfferAnswer = [ test.pcLocal.checkStatsIceConnections(stats, test._offer_constraints, test._offer_options, - test._remote_answer); + test.testOptions); }); }, @@ -492,7 +446,7 @@ var commandsPeerConnectionOfferAnswer = [ test.pcRemote.checkStatsIceConnections(stats, test._offer_constraints, test._offer_options, - test.originalAnswer); + test.testOptions); }); }, @@ -509,22 +463,46 @@ var commandsPeerConnectionOfferAnswer = [ function PC_REMOTE_CHECK_STATS(test) { return checkAllTrackStats(test.pcRemote); }, - function PC_LOCAL_WAIT_FOR_END_OF_TRICKLE(test) { - return test.pcLocal.endOfTrickleIce; + function PC_LOCAL_VERIFY_SDP_AFTER_END_OF_TRICKLE(test) { + /* In case the endOfTrickleSdp promise is resolved already it will win the + * race because it gets evaluated first. But if endOfTrickleSdp is still + * pending the rejection will win the race. */ + return Promise.race([ + test.pcLocal.endOfTrickleSdp, + Promise.reject("No SDP") + ]) + .then(sdp => sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcLocal.label), + () => info("pcLocal: Gathering is not complete yet, skipping post-gathering SDP check")); }, - function PC_REMOTE_WAIT_FOR_END_OF_TRICKLE(test) { - return test.pcRemote.endOfTrickleIce; + function PC_REMOTE_VERIFY_SDP_AFTER_END_OF_TRICKLE(test) { + /* In case the endOfTrickleSdp promise is resolved already it will win the + * race because it gets evaluated first. But if endOfTrickleSdp is still + * pending the rejection will win the race. */ + return Promise.race([ + test.pcRemote.endOfTrickleSdp, + Promise.reject("No SDP") + ]) + .then(sdp => sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcRemote.label), + () => info("pcRemote: Gathering is not complete yet, skipping post-gathering SDP check")); } ]; +function PC_LOCAL_REMOVE_VP8_FROM_OFFER(test) { + isnot(test.originalOffer.sdp.search("H264/90000"), -1, "H.264 should be present in the SDP offer"); + test.originalOffer.sdp = sdputils.removeVP8(test.originalOffer.sdp); + info("Updated H264 only offer: " + JSON.stringify(test.originalOffer)); +}; + function PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER(test) { - test.originalOffer.sdp = test.originalOffer.sdp.replace( - /a=group:BUNDLE .*\r\n/g, - "" - ); + test.originalOffer.sdp = sdputils.removeBundle(test.originalOffer.sdp); info("Updated no bundle offer: " + JSON.stringify(test.originalOffer)); }; +function PC_LOCAL_REMOVE_RTCPMUX_FROM_OFFER(test) { + test.originalOffer.sdp = sdputils.removeRtcpMux(test.originalOffer.sdp); + info("Updated no RTCP-Mux offer: " + JSON.stringify(test.originalOffer)); +}; + var addRenegotiation = (chain, commands, checks) => { chain.append(commands); chain.append(commandsPeerConnectionOfferAnswer); diff --git a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html index 7081df0f650..dc8725f5ade 100644 --- a/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html +++ b/dom/media/tests/mochitest/test_dataChannel_basicAudioVideoNoBundle.html @@ -12,17 +12,11 @@ }); var test; -runNetworkTest(function () { - test = new PeerConnectionTest(); +runNetworkTest(function (options) { + options = options || { }; + options.bundle = false; + test = new PeerConnectionTest(options); addInitialDataChannel(test.chain); - test.chain.insertAfter("PC_LOCAL_CREATE_OFFER", [ - function PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER(test) { - // Just replace a=group:BUNDLE with something that will be ignored. - test.originalOffer.sdp = test.originalOffer.sdp.replace( - "a=group:BUNDLE", - "a=foo:"); - } - ]); test.setMediaConstraints([{audio: true}, {video: true}], [{audio: true}, {video: true}]); test.run(); diff --git a/dom/media/tests/mochitest/test_peerConnection_addDataChannelNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_addDataChannelNoBundle.html index dc91f6976d4..5182aa56495 100644 --- a/dom/media/tests/mochitest/test_peerConnection_addDataChannelNoBundle.html +++ b/dom/media/tests/mochitest/test_peerConnection_addDataChannelNoBundle.html @@ -13,6 +13,8 @@ var test; runNetworkTest(function (options) { + options = options || { }; + options.bundle = false; test = new PeerConnectionTest(options); addRenegotiation(test.chain, commandsCreateDataChannel.concat( @@ -27,9 +29,6 @@ ), commandsCheckDataChannel); - test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER', - PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER); - // Insert before the second PC_LOCAL_CHECK_MEDIA_TRACKS test.chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS', commandsWaitForDataChannel, diff --git a/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html index 99fd8e766f1..34cf99a2f89 100644 --- a/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html +++ b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStreamNoBundle.html @@ -13,6 +13,8 @@ var test; runNetworkTest(function (options) { + options = options || { }; + options.bundle = false; test = new PeerConnectionTest(options); addRenegotiation(test.chain, [ @@ -30,9 +32,6 @@ ] ); - test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER', - PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER); - // TODO(bug 1093835): figure out how to verify if media flows through the new stream test.setMediaConstraints([{audio: true}], [{audio: true}]); test.run(); diff --git a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html index 577a125e58b..a7dae4045ce 100644 --- a/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html +++ b/dom/media/tests/mochitest/test_peerConnection_addSecondVideoStreamNoBundle.html @@ -13,6 +13,8 @@ var test; runNetworkTest(function (options) { + options = options || { }; + options.bundle = false; test = new PeerConnectionTest(options); addRenegotiation(test.chain, [ @@ -30,9 +32,6 @@ ] ); - test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER', - PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER); - // TODO(bug 1093835): figure out how to verify if media flows through the new stream test.setMediaConstraints([{video: true}], [{video: true}]); test.run(); diff --git a/dom/media/tests/mochitest/test_peerConnection_basicAudioRequireEOC.html b/dom/media/tests/mochitest/test_peerConnection_basicAudioRequireEOC.html new file mode 100644 index 00000000000..e3e44cf1bf2 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioRequireEOC.html @@ -0,0 +1,35 @@ + + + + + + +
+
+
+ + diff --git a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundle.html b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundle.html index 5d58bcb90c7..c840804a6b2 100644 --- a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundle.html +++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundle.html @@ -12,10 +12,9 @@ }); runNetworkTest(options => { + options = options || { }; + options.bundle = false; var test = new PeerConnectionTest(options); - test.chain.insertAfter( - 'PC_LOCAL_CREATE_OFFER', - [PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER]); test.setMediaConstraints([{audio: true}, {video: true}], [{audio: true}, {video: true}]); test.run(); diff --git a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html new file mode 100644 index 00000000000..f9e6c81cd42 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html @@ -0,0 +1,39 @@ + + + + + + +
+
+
+ + diff --git a/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoRtcpMux.html b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoRtcpMux.html new file mode 100644 index 00000000000..da8dd2d559d --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoRtcpMux.html @@ -0,0 +1,38 @@ + + + + + + +
+
+
+ +