test_peerConnection_simulcastAnswer.html (4893B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <script type="application/javascript" src="pc.js"></script> 5 <script type="application/javascript" src="/tests/dom/canvas/test/captureStream_common.js"></script> 6 <script type="application/javascript" src="helpers_from_wpt/sdp.js"></script> 7 <script type="application/javascript" src="simulcast.js"></script> 8 <script type="application/javascript" src="stats.js"></script> 9 </head> 10 <body> 11 <pre id="test"> 12 <script type="application/javascript"> 13 createHTML({ 14 bug: "1231507", 15 title: "Basic video-only peer connection with Simulcast answer", 16 visible: true 17 }); 18 19 runNetworkTest(async () => { 20 await pushPrefs( 21 // 180Kbps was determined empirically, set well-higher than 22 // the 80Kbps+overhead needed for the two simulcast streams. 23 // 100Kbps was apparently too low. 24 ['media.peerconnection.video.min_bitrate_estimate', 180*1000]); 25 26 // [TODO] re-enable HW decoder after bug 1526207 is fixed. 27 if (navigator.userAgent.includes("Android")) { 28 await pushPrefs(["media.navigator.mediadatadecoder_vpx_enabled", false]); 29 } 30 31 32 const offerer = new RTCPeerConnection(); 33 const answerer = new RTCPeerConnection(); 34 35 const add = (pc, can, failed) => can && pc.addIceCandidate(can).catch(failed); 36 offerer.onicecandidate = e => add(answerer, e.candidate, generateErrorCallback()); 37 answerer.onicecandidate = e => add(offerer, e.candidate, generateErrorCallback()); 38 39 const metadataToBeLoaded = []; 40 offerer.ontrack = (e) => { 41 metadataToBeLoaded.push(getPlaybackWithLoadedMetadata(e.track)); 42 }; 43 44 // Two recv transceivers, one for each simulcast stream 45 offerer.addTransceiver('video', { direction: 'recvonly' }); 46 offerer.addTransceiver('video', { direction: 'recvonly' }); 47 48 const offer = await offerer.createOffer(); 49 50 const mungedOffer = midToRid(offer); 51 info(`Transformed recv offer to simulcast: ${offer.sdp} to ${mungedOffer}`); 52 53 await answerer.setRemoteDescription({type: 'offer', sdp: mungedOffer}); 54 55 // One send transceiver, that will be used to send both simulcast streams 56 const emitter = new VideoFrameEmitter(); 57 const videoStream = emitter.stream(); 58 const sender = answerer.addTrack(videoStream.getVideoTracks()[0], videoStream); 59 let parameters = sender.getParameters(); 60 is(parameters.encodings.length, 2); 61 is(answerer.getSenders().length, 1); 62 emitter.start(); 63 64 await offerer.setLocalDescription(offer); 65 66 const rids = offerer.getTransceivers().map(t => t.mid); 67 is(rids.length, 2, 'Should have 2 mids in offer'); 68 ok(rids[0] != '', 'First mid should be non-empty'); 69 ok(rids[1] != '', 'Second mid should be non-empty'); 70 info(`rids: ${JSON.stringify(rids)}`); 71 72 parameters = sender.getParameters(); 73 info(`parameters: ${JSON.stringify(parameters)}`); 74 const observedRids = parameters.encodings.map(({rid}) => rid); 75 isDeeply(observedRids, rids); 76 parameters.encodings[0].maxBitrate = 40000; 77 parameters.encodings[0].scaleResolutionDownBy = 1; 78 parameters.encodings[1].maxBitrate = 40000; 79 parameters.encodings[1].scaleResolutionDownBy = 2; 80 await sender.setParameters(parameters); 81 82 const answer = await answerer.createAnswer(); 83 84 const mungedAnswer = ridToMid(answer); 85 info(`Transformed send simulcast answer to multiple m-sections: ${answer.sdp} to ${mungedAnswer}`); 86 await offerer.setRemoteDescription({type: 'answer', sdp: mungedAnswer}); 87 await answerer.setLocalDescription(answer); 88 89 is(metadataToBeLoaded.length, 2, 'Offerer should have gotten 2 ontrack events'); 90 info('Waiting for 2 loadedmetadata events'); 91 const videoElems = await Promise.all(metadataToBeLoaded); 92 93 const statsReady = 94 Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]); 95 96 const helper = new VideoStreamHelper(); 97 info('Waiting for first video element to start playing'); 98 await helper.checkVideoPlaying(videoElems[0]); 99 info('Waiting for second video element to start playing'); 100 await helper.checkVideoPlaying(videoElems[1]); 101 102 is(videoElems[0].videoWidth, 64, 103 "sink is same width as source, modulo our cropping algorithm"); 104 is(videoElems[0].videoHeight, 64, 105 "sink is same height as source, modulo our cropping algorithm"); 106 is(videoElems[1].videoWidth, 32, 107 "sink is 1/2 width of source, modulo our cropping algorithm"); 108 is(videoElems[1].videoHeight, 32, 109 "sink is 1/2 height of source, modulo our cropping algorithm"); 110 111 await statsReady; 112 info("Stats ready"); 113 const senderStats = await sender.getStats(); 114 checkSenderStats(senderStats, 2); 115 checkExpectedFields(senderStats); 116 pedanticChecks(senderStats); 117 118 emitter.stop(); 119 videoStream.getVideoTracks()[0].stop(); 120 offerer.close(); 121 answerer.close(); 122 }); 123 </script> 124 </pre> 125 </body> 126 </html>