test_peerConnection_simulcastAnswer_lowResFirst.html (4599B)
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, first rid has lowest resolution", 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 // One send transceiver, that will be used to send both simulcast streams 49 const emitter = new VideoFrameEmitter(); 50 const videoStream = emitter.stream(); 51 answerer.addTrack(videoStream.getVideoTracks()[0], videoStream); 52 emitter.start(); 53 54 const offer = await offerer.createOffer(); 55 56 const mungedOffer = midToRid(offer); 57 info(`Transformed recv offer to simulcast: ${offer.sdp} to ${mungedOffer}`); 58 59 await answerer.setRemoteDescription({type: 'offer', sdp: mungedOffer}); 60 await offerer.setLocalDescription(offer); 61 62 const rids = offerer.getTransceivers().map(t => t.mid); 63 is(rids.length, 2, 'Should have 2 mids in offer'); 64 ok(rids[0] != '', 'First mid should be non-empty'); 65 ok(rids[1] != '', 'Second mid should be non-empty'); 66 info(`rids: ${JSON.stringify(rids)}`); 67 68 const sender = answerer.getSenders()[0]; 69 const parameters = sender.getParameters(); 70 parameters.encodings[0].maxBitrate = 40000; 71 parameters.encodings[0].scaleResolutionDownBy = 2; 72 parameters.encodings[1].maxBitrate = 40000; 73 await sender.setParameters(parameters); 74 75 const answer = await answerer.createAnswer(); 76 77 const mungedAnswer = ridToMid(answer); 78 info(`Transformed send simulcast answer to multiple m-sections: ${answer.sdp} to ${mungedAnswer}`); 79 await offerer.setRemoteDescription({type: 'answer', sdp: mungedAnswer}); 80 await answerer.setLocalDescription(answer); 81 82 is(metadataToBeLoaded.length, 2, 'Offerer should have gotten 2 ontrack events'); 83 info('Waiting for 2 loadedmetadata events'); 84 const videoElems = await Promise.all(metadataToBeLoaded); 85 86 const statsReady = 87 Promise.all([waitForSyncedRtcp(offerer), waitForSyncedRtcp(answerer)]); 88 89 const helper = new VideoStreamHelper(); 90 info('Waiting for first video element to start playing'); 91 await helper.checkVideoPlaying(videoElems[0]); 92 info('Waiting for second video element to start playing'); 93 await helper.checkVideoPlaying(videoElems[1]); 94 95 is(videoElems[1].videoWidth, 64, 96 "sink is same width as source, modulo our cropping algorithm"); 97 is(videoElems[1].videoHeight, 64, 98 "sink is same height as source, modulo our cropping algorithm"); 99 is(videoElems[0].videoWidth, 32, 100 "sink is 1/2 width of source, modulo our cropping algorithm"); 101 is(videoElems[0].videoHeight, 32, 102 "sink is 1/2 height of source, modulo our cropping algorithm"); 103 104 await statsReady; 105 const senderStats = await sender.getStats(); 106 checkSenderStats(senderStats, 2); 107 checkExpectedFields(senderStats); 108 pedanticChecks(senderStats); 109 110 emitter.stop(); 111 videoStream.getVideoTracks()[0].stop(); 112 offerer.close(); 113 answerer.close(); 114 }); 115 </script> 116 </pre> 117 </body> 118 </html>