<!doctype html>
<meta charset=utf-8>
<title>RTCPeerConnection Insertable Streams Simulcast</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=/resources/testdriver.js></script>
<script src=/resources/testdriver-vendor.js></script>
<script src='../../mediacapture-streams/permission-helper.js'></script>
<script src="../../webrtc/RTCPeerConnection-helper.js"></script>
<script src="../../webrtc/third_party/sdp/sdp.js"></script>
<script src="../../webrtc/simulcast/simulcast.js"></script>
<script>
// Test based on wpt/webrtc/simulcast/basic.https.html
promise_test(async t => {
const rids = [0, 1, 2];
const pc1 = new RTCPeerConnection({encodedInsertableStreams:true});
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection({encodedInsertableStreams:true});
t.add_cleanup(() => pc2.close());
exchangeIceCandidates(pc1, pc2);
const metadataToBeLoaded = [];
let receiverSSRCs = []
pc2.ontrack = t.step_func(e => {
const receiverTransformer = new TransformStream({
async transform(encodedFrame, controller) {
let ssrc = encodedFrame.getMetadata().synchronizationSource;
if (receiverSSRCs.indexOf(ssrc) == -1)
receiverSSRCs.push(ssrc);
controller.enqueue(encodedFrame);
}
});
const receiverStreams = e.receiver.createEncodedStreams();
receiverStreams.readable
.pipeThrough(receiverTransformer)
.pipeTo(receiverStreams.writable);
const stream = e.streams[0];
const v = document.createElement('video');
v.autoplay = true;
v.srcObject = stream;
v.id = stream.id
metadataToBeLoaded.push(new Promise((resolve) => {
v.addEventListener('loadedmetadata', () => {
resolve();
});
}));
});
await setMediaPermission("granted", ["camera"]);
const stream = await navigator.mediaDevices.getUserMedia({video: {width: 1280, height: 720}});
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
const transceiver = pc1.addTransceiver(stream.getVideoTracks()[0], {
streams: [stream],
sendEncodings: rids.map(rid => {rid}),
});
const senderStreams = transceiver.sender.createEncodedStreams();
let senderSSRCs = [];
const senderTransformer = new TransformStream({
async transform(encodedFrame, controller) {
if (senderSSRCs.indexOf(encodedFrame.getMetadata().synchronizationSource) == -1)
senderSSRCs.push(encodedFrame.getMetadata().synchronizationSource);
controller.enqueue(encodedFrame);
}
});
senderStreams.readable
.pipeThrough(senderTransformer)
.pipeTo(senderStreams.writable);
const offer = await pc1.createOffer();
await pc1.setLocalDescription(offer),
await pc2.setRemoteDescription({
type: 'offer',
sdp: swapRidAndMidExtensionsInSimulcastOffer(offer, rids),
});
const answer = await pc2.createAnswer();
await pc2.setLocalDescription(answer);
await pc1.setRemoteDescription({
type: 'answer',
sdp: swapRidAndMidExtensionsInSimulcastAnswer(answer, pc1.localDescription, rids),
});
assert_equals(metadataToBeLoaded.length, 3);
await Promise.all(metadataToBeLoaded);
// Ensure that frames from the 3 simulcast layers are exposed.
assert_equals(senderSSRCs.length, 3);
assert_equals(receiverSSRCs.length, 3);
}, 'Basic simulcast setup with three spatial layers');
</script>