зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1167443 - Fix verification of end-of-candidates in mochitests. r=mt
--HG-- rename : dom/media/tests/mochitest/test_peerConnection_basicAudio.html => dom/media/tests/mochitest/test_peerConnection_basicAudioRequireEOC.html rename : dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html => dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoBundleNoRtcpMux.html rename : dom/media/tests/mochitest/test_peerConnection_basicAudioVideo.html => dom/media/tests/mochitest/test_peerConnection_basicAudioVideoNoRtcpMux.html extra : amend_source : 88d5de7099179bfd062ef32bb7576d1a3377f5e2 extra : transplant_source : C%EF%B0%20%891o%C6%3C%D2/%B3%E16%AF%A1%B8%F9G%29
This commit is contained in:
Родитель
9baa6bf56b
Коммит
bd24d821b8
|
@ -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]
|
||||
|
|
|
@ -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) !== '/') {
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1167443",
|
||||
title: "Basic audio-only peer connection which waits for end-of-candidates"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.chain.replace("PC_LOCAL_VERIFY_SDP_AFTER_END_OF_TRICKLE", [
|
||||
function PC_LOCAL_REQUIRE_SDP_AFTER_END_OF_TRICKLE(test) {
|
||||
return test.pcLocal.endOfTrickleSdp.then(sdp =>
|
||||
sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcLocal.label));
|
||||
}
|
||||
]);
|
||||
test.chain.replace("PC_REMOTE_VERIFY_SDP_AFTER_END_OF_TRICKLE", [
|
||||
function PC_REMOTE_REQUIRE_SDP_AFTER_END_OF_TRICKLE(test) {
|
||||
return test.pcRemote.endOfTrickleSdp.then(sdp =>
|
||||
sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcRemote.label));
|
||||
}
|
||||
]);
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</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();
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1167443",
|
||||
title: "Basic audio & video call with disabled bundle and disbaled RTCP-Mux"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
options = options || { };
|
||||
options.bundle = false;
|
||||
options.rtcpmux = false;
|
||||
test = new PeerConnectionTest(options);
|
||||
test.chain.replace("PC_LOCAL_VERIFY_SDP_AFTER_END_OF_TRICKLE", [
|
||||
function PC_LOCAL_REQUIRE_SDP_AFTER_END_OF_TRICKLE(test) {
|
||||
return test.pcLocal.endOfTrickleSdp .then(sdp =>
|
||||
sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcLocal.label));
|
||||
}
|
||||
]);
|
||||
test.chain.replace("PC_REMOTE_VERIFY_SDP_AFTER_END_OF_TRICKLE", [
|
||||
function PC_REMOTE_REQUIRE_SDP_AFTER_END_OF_TRICKLE(test) {
|
||||
return test.pcRemote.endOfTrickleSdp .then(sdp =>
|
||||
sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcRemote.label));
|
||||
}
|
||||
]);
|
||||
test.setMediaConstraints([{audio: true}, {video: true}],
|
||||
[{audio: true}, {video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1167443",
|
||||
title: "Basic audio & video call with disabled RTCP-Mux"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
options = options || { };
|
||||
options.rtcpmux = false;
|
||||
test = new PeerConnectionTest(options);
|
||||
test.chain.replace("PC_LOCAL_VERIFY_SDP_AFTER_END_OF_TRICKLE", [
|
||||
function PC_LOCAL_REQUIRE_SDP_AFTER_END_OF_TRICKLE(test) {
|
||||
return test.pcLocal.endOfTrickleSdp .then(sdp =>
|
||||
sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcLocal.label));
|
||||
}
|
||||
]);
|
||||
test.chain.replace("PC_REMOTE_VERIFY_SDP_AFTER_END_OF_TRICKLE", [
|
||||
function PC_REMOTE_REQUIRE_SDP_AFTER_END_OF_TRICKLE(test) {
|
||||
return test.pcRemote.endOfTrickleSdp .then(sdp =>
|
||||
sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcRemote.label));
|
||||
}
|
||||
]);
|
||||
test.setMediaConstraints([{audio: true}, {video: true}],
|
||||
[{audio: true}, {video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче