mirror of
https://github.com/servo/servo.git
synced 2025-08-28 16:48:22 +01:00
Update web-platform-tests to revision d7afcb8708eac08a614d161d5622a48172daf7e3
This commit is contained in:
parent
6f8bb4dd40
commit
edff458e23
791 changed files with 17647 additions and 10322 deletions
|
@ -78,13 +78,24 @@ function createDtmfSender(pc = new RTCPeerConnection()) {
|
|||
Test description.
|
||||
*/
|
||||
function test_tone_change_events(testFunc, toneChanges, desc) {
|
||||
async_test(t => {
|
||||
// Convert to cumulative time
|
||||
let cumulativeTime = 0;
|
||||
const cumulativeToneChanges = toneChanges.map(c => {
|
||||
cumulativeTime += c[2];
|
||||
return [c[0], c[1], cumulativeTime];
|
||||
});
|
||||
|
||||
// Wait for same duration as last expected duration + 100ms
|
||||
// before passing test in case there are new tone events fired,
|
||||
// in which case the test should fail.
|
||||
const lastWait = toneChanges.pop()[2] + 100;
|
||||
|
||||
promise_test(async t => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const dtmfSender = await createDtmfSender(pc);
|
||||
const start = Date.now();
|
||||
|
||||
createDtmfSender(pc)
|
||||
.then(dtmfSender => {
|
||||
let lastEventTime = Date.now();
|
||||
|
||||
const allEventsReceived = new Promise(resolve => {
|
||||
const onToneChange = t.step_func(ev => {
|
||||
assert_true(ev instanceof RTCDTMFToneChangeEvent,
|
||||
'Expect tone change event object to be an RTCDTMFToneChangeEvent');
|
||||
|
@ -93,12 +104,12 @@ function test_tone_change_events(testFunc, toneChanges, desc) {
|
|||
assert_equals(typeof tone, 'string',
|
||||
'Expect event.tone to be the tone string');
|
||||
|
||||
assert_greater_than(toneChanges.length, 0,
|
||||
assert_greater_than(cumulativeToneChanges.length, 0,
|
||||
'More tonechange event is fired than expected');
|
||||
|
||||
const [
|
||||
expectedTone, expectedToneBuffer, expectedDuration
|
||||
] = toneChanges.shift();
|
||||
expectedTone, expectedToneBuffer, expectedTime
|
||||
] = cumulativeToneChanges.shift();
|
||||
|
||||
assert_equals(tone, expectedTone,
|
||||
`Expect current event.tone to be ${expectedTone}`);
|
||||
|
@ -106,37 +117,24 @@ function test_tone_change_events(testFunc, toneChanges, desc) {
|
|||
assert_equals(dtmfSender.toneBuffer, expectedToneBuffer,
|
||||
`Expect dtmfSender.toneBuffer to be updated to ${expectedToneBuffer}`);
|
||||
|
||||
const now = Date.now();
|
||||
const duration = now - lastEventTime;
|
||||
|
||||
// We check that the delay is at least the expected one, but
|
||||
// system load may cause random delay, so we do not put any
|
||||
// realistic upper bound on the timing of the event.
|
||||
assert_between_inclusive(duration, expectedDuration,
|
||||
expectedDuration + 4000,
|
||||
`Expect tonechange event for "${tone}" to be fired approximately after ${expectedDuration} milliseconds`);
|
||||
|
||||
lastEventTime = now;
|
||||
|
||||
if (toneChanges.length === 0) {
|
||||
// Wait for same duration as last expected duration + 100ms
|
||||
// before passing test in case there are new tone events fired,
|
||||
// in which case the test should fail.
|
||||
t.step_timeout(
|
||||
t.step_func(() => {
|
||||
t.done();
|
||||
pc.close();
|
||||
pc.otherPc.close();
|
||||
}), expectedDuration + 100);
|
||||
// We check that the cumulative delay is at least the expected one, but
|
||||
// system load may cause random delays, so we do not put any
|
||||
// realistic upper bound on the timing of the events.
|
||||
assert_between_inclusive(Date.now() - start, expectedTime,
|
||||
expectedTime + 4000,
|
||||
`Expect tonechange event for "${tone}" to be fired approximately after ${expectedTime} milliseconds`);
|
||||
if (cumulativeToneChanges.length === 0) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
dtmfSender.addEventListener('tonechange', onToneChange);
|
||||
testFunc(t, dtmfSender, pc);
|
||||
})
|
||||
.catch(t.step_func(err => {
|
||||
assert_unreached(`Unexpected promise rejection: ${err}`);
|
||||
}));
|
||||
});
|
||||
|
||||
testFunc(t, dtmfSender, pc);
|
||||
await allEventsReceived;
|
||||
const wait = ms => new Promise(resolve => t.step_timeout(resolve, ms));
|
||||
await wait(lastWait);
|
||||
}, desc);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
if(dtlsTransport.state === 'connected') {
|
||||
onConnected(dtlsTransport);
|
||||
} else {
|
||||
assert_array_equals(dtlsTransport.getCertificates(), [],
|
||||
assert_array_equals(dtlsTransport.getRemoteCertificates(), [],
|
||||
'Expect DTLS certificates be initially empty until become connected');
|
||||
|
||||
dtlsTransport.addEventListener('statechange', t.step_func(() => {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
'use strict';
|
||||
|
||||
// The following helper functions are called from RTCPeerConnection-helper.js:
|
||||
// exchangeIceCandidates
|
||||
// coupleIceCandidates
|
||||
// doSignalingHandshake
|
||||
// trackFactories.audio()
|
||||
|
||||
|
@ -42,36 +42,6 @@ function resolveWhen(t, dtlstransport, state) {
|
|||
});
|
||||
}
|
||||
|
||||
// Helper class to exchange ice candidates between
|
||||
// two local peer connections
|
||||
class CandidateChannel {
|
||||
constructor(source, dest) {
|
||||
source.addEventListener('icecandidate', event => {
|
||||
const { candidate } = event;
|
||||
if (candidate && this.activated
|
||||
&& this.destination.signalingState !== 'closed') {
|
||||
this.destination.addIceCandidate(candidate);
|
||||
} else {
|
||||
this.queue.push(candidate);
|
||||
}
|
||||
});
|
||||
this.destination = dest;
|
||||
this.activated = false;
|
||||
this.queue = [];
|
||||
}
|
||||
activate() {
|
||||
this.activated = true;
|
||||
for (const candidate of this.queue) {
|
||||
this.destination.addIceCandidate(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function coupleCandidates(pc1, pc2) {
|
||||
const ch1 = new CandidateChannel(pc1, pc2);
|
||||
const ch2 = new CandidateChannel(pc2, pc1);
|
||||
return [ch1, ch2];
|
||||
}
|
||||
|
||||
async function setupConnections(t) {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
|
@ -80,11 +50,8 @@ async function setupConnections(t) {
|
|||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
pc1.addTrack(trackFactories.audio());
|
||||
const channels = coupleCandidates(pc1, pc2);
|
||||
const channels = coupleIceCandidates(pc1, pc2);
|
||||
await doSignalingHandshake(pc1, pc2);
|
||||
for (const channel of channels) {
|
||||
channel.activate();
|
||||
}
|
||||
return [pc1, pc2];
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,46 @@ function exchangeIceCandidates(pc1, pc2) {
|
|||
doExchange(pc2, pc1);
|
||||
}
|
||||
|
||||
// Helper class to exchange ice candidates between
|
||||
// two local peer connections
|
||||
class CandidateChannel {
|
||||
constructor(source, dest, name) {
|
||||
source.addEventListener('icecandidate', event => {
|
||||
const { candidate } = event;
|
||||
if (candidate && this.activated
|
||||
&& this.destination.signalingState !== 'closed') {
|
||||
this.destination.addIceCandidate(candidate);
|
||||
} else if (candidate) {
|
||||
this.queue.push(candidate);
|
||||
}
|
||||
});
|
||||
dest.addEventListener('signalingstatechange', event => {
|
||||
if (this.destination.signalingState == 'stable' && !this.activated) {
|
||||
this.activate();
|
||||
}
|
||||
});
|
||||
this.name = name;
|
||||
this.destination = dest;
|
||||
this.activated = false;
|
||||
this.queue = [];
|
||||
}
|
||||
activate() {
|
||||
this.activated = true;
|
||||
for (const candidate of this.queue) {
|
||||
this.destination.addIceCandidate(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Alternate function to exchange ICE candidates between two
|
||||
// PeerConnections. Unlike exchangeIceCandidates, it will function
|
||||
// correctly if candidates are added before descriptions are set.
|
||||
function coupleIceCandidates(pc1, pc2) {
|
||||
const ch1 = new CandidateChannel(pc1, pc2, 'forward');
|
||||
const ch2 = new CandidateChannel(pc2, pc1, 'back');
|
||||
return [ch1, ch2];
|
||||
}
|
||||
|
||||
// Helper function for doing one round of offer/answer exchange
|
||||
// between two local peer connections
|
||||
async function doSignalingHandshake(localPc, remotePc, options={}) {
|
||||
|
@ -200,9 +240,9 @@ async function doSignalingHandshake(localPc, remotePc, options={}) {
|
|||
answer = await options.modifyAnswer(answer);
|
||||
}
|
||||
|
||||
// Apply answer
|
||||
await remotePc.setLocalDescription(answer);
|
||||
// Apply answer. Note: localPc should enter stable state first.
|
||||
await localPc.setRemoteDescription(answer);
|
||||
await remotePc.setLocalDescription(answer);
|
||||
}
|
||||
|
||||
// Returns a promise that resolves when |pc.iceConnectionState| is 'connected'
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
|
||||
|
||||
// The following helper functions are called from RTCPeerConnection-helper.js:
|
||||
// exchangeIceCandidates
|
||||
// coupleIceCandidates
|
||||
// doSignalingHandshake
|
||||
|
||||
/*
|
||||
|
@ -132,7 +132,7 @@
|
|||
|
||||
pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
|
||||
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
coupleIceCandidates(pc1, pc2);
|
||||
doSignalingHandshake(pc1, pc2);
|
||||
}, 'connection with one data channel should eventually have connected or ' +
|
||||
'completed connection state');
|
||||
|
@ -178,11 +178,43 @@ async_test(t => {
|
|||
|
||||
pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
|
||||
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
coupleIceCandidates(pc1, pc2);
|
||||
doSignalingHandshake(pc1, pc2);
|
||||
}, 'connection with one data channel should eventually ' +
|
||||
'have connected connection state');
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
stream.getTracks().forEach(track => pc1.addTrack(track, stream));
|
||||
|
||||
coupleIceCandidates(pc1, pc2);
|
||||
doSignalingHandshake(pc1, pc2);
|
||||
await listenToIceConnected(pc1);
|
||||
}, 'connection with audio track should eventually ' +
|
||||
'have connected connection state');
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream = await getNoiseStream({audio: true, video:true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
stream.getTracks().forEach(track => pc1.addTrack(track, stream));
|
||||
|
||||
coupleIceCandidates(pc1, pc2);
|
||||
doSignalingHandshake(pc1, pc2);
|
||||
await listenToIceConnected(pc1);
|
||||
}, 'connection with audio and video tracks should eventually ' +
|
||||
'have connected connection state');
|
||||
|
||||
promise_test(async t => {
|
||||
const caller = new RTCPeerConnection();
|
||||
t.add_cleanup(() => caller.close());
|
||||
|
@ -191,9 +223,10 @@ async_test(t => {
|
|||
|
||||
caller.addTransceiver('audio', {direction:'recvonly'});
|
||||
const stream = await navigator.mediaDevices.getUserMedia({audio:true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track] = stream.getTracks();
|
||||
callee.addTrack(track, stream);
|
||||
exchangeIceCandidates(caller, callee);
|
||||
coupleIceCandidates(caller, callee);
|
||||
await doSignalingHandshake(caller, callee);
|
||||
|
||||
assert_equals(caller.getTransceivers().length, 1);
|
||||
|
|
|
@ -100,8 +100,28 @@ promise_test(async t => {
|
|||
await unmutePromise;
|
||||
|
||||
const mutePromise = muteWatcher.wait_for('mute');
|
||||
pc2.close();
|
||||
localTransceiver.stop();
|
||||
await mutePromise;
|
||||
}, 'pc.close() mutes remote tracks');
|
||||
}, 'transceiver.stop() on one side (without renegotiation) causes mute events on the other');
|
||||
|
||||
promise_test(async t => {
|
||||
const pc1 = createPeerConnectionWithCleanup(t);
|
||||
const pc1Sender = pc1.addTrack(...await createTrackAndStreamWithCleanup(t));
|
||||
const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
|
||||
const pc2 = createPeerConnectionWithCleanup(t);
|
||||
exchangeIceCandidates(pc1, pc2);
|
||||
|
||||
const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
|
||||
// Need to wait for the initial unmute event before closing, otherwise
|
||||
// there will be no transition from unmuted->muted.
|
||||
const muteWatcher = new EventWatcher(t, e.track, ['mute', 'unmute']);
|
||||
const unmutePromise = muteWatcher.wait_for('unmute');
|
||||
await exchangeAnswer(pc1, pc2);
|
||||
await unmutePromise;
|
||||
|
||||
const mutePromise = muteWatcher.wait_for('mute');
|
||||
pc1.close();
|
||||
await mutePromise;
|
||||
}, 'pc.close() on one side causes mute events on the other');
|
||||
|
||||
</script>
|
||||
|
|
|
@ -86,5 +86,67 @@
|
|||
assert_equals(caller_transceiver1.receiver.transport,
|
||||
caller_transceiver2.receiver.transport);
|
||||
}, 'RTCRtpSender/receiver.transport at the right time, with bundle policy ' + bundle_policy);
|
||||
|
||||
// Do the same test again, with DataChannel in the mix.
|
||||
promise_test(async t => {
|
||||
const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
|
||||
t.add_cleanup(() => caller.close());
|
||||
const stream = await navigator.mediaDevices.getUserMedia(
|
||||
{audio: true, video:true});
|
||||
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
||||
const [track1, track2] = stream.getTracks();
|
||||
const sender1 = caller.addTrack(track1);
|
||||
const sender2 = caller.addTrack(track2);
|
||||
caller.createDataChannel('datachannel');
|
||||
const callee = new RTCPeerConnection();
|
||||
t.add_cleanup(() => callee.close());
|
||||
exchangeIceCandidates(caller, callee);
|
||||
const offer = await caller.createOffer();
|
||||
assert_equals(sender1.transport, null);
|
||||
assert_equals(sender2.transport, null);
|
||||
if (caller.sctp) {
|
||||
assert_equals(caller.sctp.transport, null);
|
||||
}
|
||||
await caller.setLocalDescription(offer);
|
||||
assert_not_equals(sender1.transport, null);
|
||||
assert_not_equals(sender2.transport, null);
|
||||
assert_not_equals(caller.sctp.transport, null);
|
||||
const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
|
||||
assert_equals(sender1.transport, caller_transceiver1.sender.transport);
|
||||
if (bundle_policy == 'max-bundle') {
|
||||
assert_equals(caller_transceiver1.sender.transport,
|
||||
caller_transceiver2.sender.transport);
|
||||
assert_equals(caller_transceiver1.sender.transport,
|
||||
caller.sctp.transport);
|
||||
} else {
|
||||
assert_not_equals(caller_transceiver1.sender.transport,
|
||||
caller_transceiver2.sender.transport);
|
||||
assert_not_equals(caller_transceiver1.sender.transport,
|
||||
caller.sctp.transport);
|
||||
}
|
||||
await callee.setRemoteDescription(offer);
|
||||
const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
|
||||
// According to spec, setRemoteDescription only updates the transports
|
||||
// if the remote description is an answer.
|
||||
assert_equals(callee_transceiver1.receiver.transport, null);
|
||||
assert_equals(callee_transceiver2.receiver.transport, null);
|
||||
const answer = await callee.createAnswer();
|
||||
await callee.setLocalDescription(answer);
|
||||
assert_not_equals(callee_transceiver1.receiver.transport, null);
|
||||
assert_not_equals(callee_transceiver2.receiver.transport, null);
|
||||
assert_not_equals(callee.sctp.transport, null);
|
||||
// At this point, bundle should have kicked in.
|
||||
assert_equals(callee_transceiver1.receiver.transport,
|
||||
callee_transceiver2.receiver.transport);
|
||||
assert_equals(callee_transceiver1.receiver.transport,
|
||||
callee.sctp.transport,
|
||||
'Callee SCTP transport does not match:');
|
||||
await caller.setRemoteDescription(answer);
|
||||
assert_equals(caller_transceiver1.receiver.transport,
|
||||
caller_transceiver2.receiver.transport);
|
||||
assert_equals(caller_transceiver1.receiver.transport,
|
||||
caller.sctp.transport,
|
||||
'Caller SCTP transport does not match:');
|
||||
}, 'RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy ' + bundle_policy);
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
RTCRtpTransceiver on which the method is called. Additionally, the
|
||||
RTCRtpCodecParameters dictionary members cannot be modified. If
|
||||
codecs does not fulfill these requirements, the user agent MUST throw
|
||||
an InvalidAccessError.
|
||||
an InvalidModificationError.
|
||||
*/
|
||||
|
||||
test(() => {
|
||||
|
@ -81,9 +81,23 @@
|
|||
const pc = new RTCPeerConnection();
|
||||
const transceiver = pc.addTransceiver('audio');
|
||||
const capabilities = RTCRtpSender.getCapabilities('video');
|
||||
assert_throws(() => transceiver.setCodecPreferences(capabilities.codecs));
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(capabilities.codecs));
|
||||
|
||||
}, `setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidAccessError`);
|
||||
}, `setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const transceiver = pc.addTransceiver('audio');
|
||||
const codecs = [{
|
||||
mimeType: 'data',
|
||||
clockRate: 2000,
|
||||
channels: 2,
|
||||
sdpFmtpLine: '0-15'
|
||||
}];
|
||||
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with user defined codec with invalid mimeType should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
|
@ -92,12 +106,12 @@
|
|||
mimeType: 'audio/piepiper',
|
||||
clockRate: 2000,
|
||||
channels: 2,
|
||||
sdpFmtpLine: 'a=fmtp:98 0-15'
|
||||
sdpFmtpLine: '0-15'
|
||||
}];
|
||||
|
||||
assert_throws(() => transceiver.setCodecPreferences(codecs));
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with user defined codec should throw InvalidAccessError`);
|
||||
}, `setCodecPreferences() with user defined codec should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
|
@ -109,12 +123,45 @@
|
|||
mimeType: 'audio/piepiper',
|
||||
clockRate: 2000,
|
||||
channels: 2,
|
||||
sdpFmtpLine: 'a=fmtp:98 0-15'
|
||||
sdpFmtpLine: '0-15'
|
||||
}];
|
||||
|
||||
assert_throws(() => transceiver.setCodecPreferences(codecs));
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidAccessError`);
|
||||
}, `setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const transceiver = pc.addTransceiver('audio');
|
||||
const capabilities = RTCRtpSender.getCapabilities('audio');
|
||||
const codecs = [capabilities.codecs[0]];
|
||||
codecs[0].clockRate = codecs[0].clockRate / 2;
|
||||
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with modified codec clock rate should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const transceiver = pc.addTransceiver('audio');
|
||||
const capabilities = RTCRtpSender.getCapabilities('audio');
|
||||
const codecs = [capabilities.codecs[0]];
|
||||
codecs[0].channels = codecs[0].channels + 11;
|
||||
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with modified codec channel count should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
const transceiver = pc.addTransceiver('audio');
|
||||
const capabilities = RTCRtpSender.getCapabilities('audio');
|
||||
const codecs = [capabilities.codecs[0]];
|
||||
codecs[0].sdpFmtpLine = "modifiedparameter=1";
|
||||
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with modified codec parameters should throw InvalidModificationError`);
|
||||
|
||||
test(() => {
|
||||
const pc = new RTCPeerConnection();
|
||||
|
@ -129,8 +176,8 @@
|
|||
const { channels=2 } = codec;
|
||||
codec.channels = channels+1;
|
||||
|
||||
assert_throws(() => transceiver.setCodecPreferences(codecs));
|
||||
assert_throws('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
|
||||
|
||||
}, `setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidAccessError`);
|
||||
}, `setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidModificationError`);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -1972,6 +1972,30 @@
|
|||
]);
|
||||
};
|
||||
|
||||
const checkBundleTagRejected = async t => {
|
||||
const pc1 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc1.close());
|
||||
const pc2 = new RTCPeerConnection();
|
||||
t.add_cleanup(() => pc2.close());
|
||||
|
||||
const stream1 = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream1));
|
||||
const track1 = stream1.getAudioTracks()[0];
|
||||
const stream2 = await getNoiseStream({audio: true});
|
||||
t.add_cleanup(() => stopTracks(stream2));
|
||||
const track2 = stream2.getAudioTracks()[0];
|
||||
|
||||
pc1.addTrack(track1, stream1);
|
||||
pc1.addTrack(track2, stream2);
|
||||
|
||||
await offerAnswer(pc1, pc2);
|
||||
|
||||
pc2.getTransceivers()[0].stop();
|
||||
|
||||
await offerAnswer(pc1, pc2);
|
||||
await offerAnswer(pc2, pc1);
|
||||
};
|
||||
|
||||
const checkMsectionReuse = async t => {
|
||||
// Use max-compat to make it easier to check for disabled m-sections
|
||||
const pc1 = new RTCPeerConnection({ bundlePolicy: "max-compat" });
|
||||
|
@ -2254,7 +2278,9 @@ const tests = [
|
|||
checkRollbackAndSetRemoteOfferWithDifferentType,
|
||||
checkRemoteRollback,
|
||||
checkMsectionReuse,
|
||||
checkStopAfterCreateOfferWithReusedMsection
|
||||
checkStopAfterCreateOfferWithReusedMsection,
|
||||
checkAddIceCandidateToStoppedTransceiver,
|
||||
checkBundleTagRejected
|
||||
].forEach(test => promise_test(test, test.name));
|
||||
|
||||
</script>
|
||||
|
|
|
@ -36,6 +36,23 @@ a=ssrc:3 cname:4
|
|||
a=ssrc:3 msid:1 2
|
||||
`;
|
||||
|
||||
const sdp2 = sdpBase + `
|
||||
a=ssrc:3 cname:4
|
||||
a=ssrc:3 msid:1 2
|
||||
`;
|
||||
|
||||
const sdp3 = sdpBase + `
|
||||
a=msid:1 2
|
||||
a=ssrc:3 cname:4
|
||||
a=ssrc:3 msid:3 2
|
||||
`;
|
||||
|
||||
const sdp4 = sdp1.replace('msid-semantic', 'unknownattr');
|
||||
|
||||
const sdp5 = sdpBase + `
|
||||
a=msid:-
|
||||
`;
|
||||
|
||||
async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp)
|
||||
{
|
||||
const testTrackPromise = new Promise(resolve => {
|
||||
|
@ -45,6 +62,64 @@ async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp)
|
|||
return testTrackPromise;
|
||||
}
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
||||
const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);
|
||||
assert_equals(streams.length, 1, "track event has a stream");
|
||||
}, "When a=msid is absent, the track should still be associated with a stream");
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
||||
const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
|
||||
assert_equals(streams.length, 1, "track event has a stream");
|
||||
assert_equals(streams[0].id, "1", "msid should match");
|
||||
}, "Source-level msid should be ignored if media-level msid is present");
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
||||
const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp2);
|
||||
assert_equals(streams.length, 1, "track event has a stream");
|
||||
assert_equals(streams[0].id, "1", "msid should match");
|
||||
}, "Source-level msid should be parsed if media-level msid is absent");
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
||||
let track;
|
||||
let streams;
|
||||
try {
|
||||
[track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp3);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
assert_equals(streams.length, 1, "track event has a stream");
|
||||
assert_equals(streams[0].id, "1", "msid should match");
|
||||
}, "Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present");
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
||||
const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp4);
|
||||
assert_equals(streams.length, 1, "track event has a stream");
|
||||
assert_equals(streams[0].id, "1", "msid should match");
|
||||
}, "stream ids should be found even if msid-semantic is absent");
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
||||
const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp5);
|
||||
assert_equals(streams.length, 0, "track event has no stream");
|
||||
}, "a=msid:- should result in a track event with no streams");
|
||||
|
||||
promise_test(async test => {
|
||||
const pc = new RTCPeerConnection();
|
||||
test.add_cleanup(() => pc.close());
|
||||
|
|
|
@ -36,9 +36,9 @@ a=rtpmap:96 VP8/90000
|
|||
a=rtcp-fb:96 goog-remb
|
||||
a=rtcp-fb:96 transport-cc
|
||||
a=rtcp-fb:96 ccm fir
|
||||
a=rid:foo send
|
||||
a=rid:bar send
|
||||
a=rid:baz send
|
||||
a=rid:foo recv
|
||||
a=rid:bar recv
|
||||
a=rid:baz recv
|
||||
a=simulcast:recv foo;bar;baz
|
||||
`;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue