<!DOCTYPE html>
<html>
<head>
<title>RTCPeerConnection Insertable Streams</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/RTCPeerConnection-helper.js"></script>
<script src='../mediacapture-streams/permission-helper.js'></script>
</head>
<body>
<script>
// Tests for the legacy variant of https://github.com/w3c/webrtc-encoded-transform
// See https://github.com/w3c/webrtc-encoded-transform/pull/111
// for the specification
promise_test(async t => {
const pc = new RTCPeerConnection({encodedInsertableStreams: true});
t.add_cleanup(() => pc.close());
const configuration = pc.getConfiguration();
assert_true(configuration.encodedInsertableStreams);
}, 'getConfiguration returns the encodedInsertableStreams parameter');
promise_test(async t => {
const pc = new RTCPeerConnection({encodedInsertableStreams: false});
t.add_cleanup(() => pc.close());
assert_throws_dom('InvalidModificationError', () => {
pc.setConfiguration({encodedInsertableStreams: true});
})
}, 'setConfiguration rejects attempts to modify the encodedInsertableStreams parameter with an InvalidModificationError');
async function getOutboundStats(videoSender) {
const stats = await videoSender.getStats();
return [...stats.values()].find(s => s.type=='outbound-rtp');
}
async function getInboundStats(videoSender) {
const stats = await videoSender.getStats();
return [...stats.values()].find(s => s.type=='inbound-rtp');
}
promise_test(async t => {
const caller = new RTCPeerConnection({encodedInsertableStreams: true});
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection();
t.add_cleanup(() => callee.close());
const stream = await navigator.mediaDevices.getUserMedia({video:true});
const videoTrack = stream.getVideoTracks()[0];
t.add_cleanup(() => videoTrack.stop());
const videoSender = caller.addTrack(videoTrack)
await exchangeIceCandidates(caller, callee);
await exchangeOfferAnswer(caller, callee);
// Wait until we've sent a frame to be transformed.
await t.step_wait(async () => {
const outboundStats = await getOutboundStats(videoSender);
assert_true(!!outboundStats);
return outboundStats.framesSent > 0;
}, "Wait for a frame to be encoded", 3000);
// Assert we've not actually sent any packets.
const outboundStats = await getOutboundStats(videoSender);
assert_equals(outboundStats.packetsSent, 0);
}, 'Senders with encodedInsertableStreams:true but no transform don\'t send packets');
promise_test(async t => {
const caller = new RTCPeerConnection();
t.add_cleanup(() => caller.close());
const callee = new RTCPeerConnection({encodedInsertableStreams: true});
t.add_cleanup(() => callee.close());
const stream = await navigator.mediaDevices.getUserMedia({video:true});
const videoTrack = stream.getVideoTracks()[0];
t.add_cleanup(() => videoTrack.stop());
const ontrackPromise = new Promise(resolve => {callee.ontrack = resolve});
const videoSender = caller.addTrack(videoTrack)
await exchangeIceCandidates(caller, callee);
await exchangeOfferAnswer(caller, callee);
await ontrackPromise;
// Wait until we've received 10 packets.
await t.step_wait(async () => {
assert_equals(callee.getReceivers().length, 1);
const inboundStats = await getInboundStats(callee.getReceivers()[0]);
assert_true(!!inboundStats);
return inboundStats.packetsReceived > 10;
}, "Wait for packets to be received", 3000);
// Assert we've not handled any frames.
const inboundStats = await getInboundStats(callee.getReceivers()[0]);
assert_equals(inboundStats.framesReceived, 0);
}, 'Receivers with encodedInsertableStreams:true but no transform don\'t receive frames');
promise_test(async t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
const transceiver = pc.addTransceiver("video");
const {readable, writable} = transceiver.sender.createEncodedStreams();
assert_true(!!readable);
assert_true(!!writable);
}, 'createEncodedStreams can be called synchronously after sender creation without encodedInsertableStreams param');
promise_test(async t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
const transceiver = pc.addTransceiver("video");
// Wait for an event loop spin.
await new Promise(resolve => setTimeout(resolve));
assert_throws_dom("InvalidStateError", () => {transceiver.sender.createEncodedStreams()});
}, 'createEncodedStreams cannot be called asynchronously after sender creation without encodedInsertableStreams param');
promise_test(async t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
const transceiver = pc.addTransceiver("video");
const {readable, writable} = transceiver.receiver.createEncodedStreams();
assert_true(!!readable);
assert_true(!!writable);
}, 'createEncodedStreams can be called synchronously after receiver creation without encodedInsertableStreams param');
promise_test(async t => {
const pc = new RTCPeerConnection();
t.add_cleanup(() => pc.close());
const transceiver = pc.addTransceiver("video");
// Wait for an event loop spin.
await new Promise(resolve => setTimeout(resolve));
assert_throws_dom("InvalidStateError", () => {transceiver.receiver.createEncodedStreams()});
}, 'createEncodedStreams cannot be called asynchronously after receiver creation without encodedInsertableStreams param');
</script>
</body>
</html>