Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!doctype html>
<meta charset=utf-8>
<title>RTCPeerConnection description attributes are replaced, not mutated, by candidates</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
const remoteCandidate = 'candidate:1 1 udp 2113929471 192.0.2.1 50000 typ host';
function assertReplaced(before, sdpBefore, after, {candidate}) {
assert_not_equals(after, before, 'attribute is a new object');
assert_equals(before.sdp, sdpBefore, 'old object sdp is unchanged');
assert_equals(after.type, before.type, 'type is preserved');
// Browsers may reorder or drop extension attributes (e.g. ufrag) in SDP.
candidate = candidate.split(' ').slice(0, 8).join(' ');
assert_false(before.sdp.includes(candidate), 'old object still lacks candidate');
assert_true(after.sdp.includes(candidate), 'new object has candidate');
}
promise_test(async t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
pc.addTransceiver('audio');
await pc.setLocalDescription();
const before = pc.pendingLocalDescription;
const sdpBefore = before.sdp;
assert_equals(pc.pendingLocalDescription, before, 'same object across gets');
const {candidate} = await new Promise(r => pc.onicecandidate = r);
assert_equals(pc.localDescription, pc.pendingLocalDescription);
assertReplaced(before, sdpBefore, pc.pendingLocalDescription, candidate);
}, 'pendingLocalDescription is replaced, not mutated, by a gathered candidate');
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.addTransceiver('audio');
await pc2.setRemoteDescription(await pc1.createOffer());
await pc2.setLocalDescription();
const before = pc2.currentLocalDescription;
const sdpBefore = before.sdp;
assert_equals(pc2.currentLocalDescription, before, 'same object across gets');
const {candidate} = await new Promise(r => pc2.onicecandidate = r);
assert_equals(pc2.localDescription, pc2.currentLocalDescription);
assertReplaced(before, sdpBefore, pc2.currentLocalDescription, candidate);
}, 'currentLocalDescription is replaced, not mutated, by a gathered candidate');
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.addTransceiver('audio');
await pc2.setRemoteDescription(await pc1.createOffer());
const before = pc2.pendingRemoteDescription;
const sdpBefore = before.sdp;
assert_equals(pc2.pendingRemoteDescription, before, 'same object across gets');
const candidate = {candidate: remoteCandidate, sdpMid: pc2.getTransceivers()[0].mid};
await pc2.addIceCandidate(candidate);
assert_equals(pc2.remoteDescription, pc2.pendingRemoteDescription);
assertReplaced(before, sdpBefore, pc2.pendingRemoteDescription, candidate);
}, 'pendingRemoteDescription is replaced, not mutated, by addIceCandidate');
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.addTransceiver('audio');
await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);
const before = pc1.currentRemoteDescription;
const sdpBefore = before.sdp;
assert_equals(pc1.currentRemoteDescription, before, 'same object across gets');
const candidate = {candidate: remoteCandidate, sdpMid: pc1.getTransceivers()[0].mid};
await pc1.addIceCandidate(candidate);
assert_equals(pc1.remoteDescription, pc1.currentRemoteDescription);
assertReplaced(before, sdpBefore, pc1.currentRemoteDescription, candidate);
}, 'currentRemoteDescription is replaced, not mutated, by addIceCandidate');
</script>