| <!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> |