RTCRtpSendParameters-degradationEffect.html (4773B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <meta name="timeout" content="long"> 4 <title>RTCRtpSendParameters degradationPreference effect</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="../webrtc/RTCPeerConnection-helper.js"></script> 8 <script> 9 'use strict'; 10 11 // This file contains tests that check that degradation preference 12 // actually has the desired effect. These tests take a long time to run. 13 14 // The signal generator will generate a video stream with at least this 15 // many bits per second if unconstrained. 16 const minUnconstrainedBandwidth = 30000; 17 18 // Returns incoming bandwidth usage between stats1 and stats2 19 // in bits per second. 20 function bandwidth(stats1, stats2) { 21 if (!stats1 || !stats2) { 22 return null; 23 } 24 const transport1 = [...stats1.values()].filter(({type}) => type === 'transport')[0]; 25 const transport2 = [...stats2.values()].filter(({type}) => type === 'transport')[0]; 26 const bytes = transport2.bytesReceived - transport1.bytesReceived; 27 // If time interval is too short for proper measurement, return null. 28 if (transport1.timestamp > transport2.timestamp - 100) { 29 return null; 30 } 31 // Multiply by 1000 to get per second, multiply by 8 to get bits. 32 const bandwidth = 1000 * 8 * bytes / 33 (transport2.timestamp - transport1.timestamp); 34 return bandwidth; 35 } 36 37 let oldStats; 38 39 // Returns tuple of { bandwidth, fps, x-res, y-res } 40 // Updates oldStats. 41 async function measureStuff(pc) { 42 const stats = await pc.getStats(); 43 if (!oldStats) { 44 oldStats = stats; 45 return {}; 46 } 47 // RTCInboundStreamStats 48 const oldRtpList = [...oldStats.values()].filter(({type}) => type === 'inbound-rtp'); 49 const inboundRtpList = [...stats.values()].filter(({type}) => type === 'inbound-rtp'); 50 const oldRtp = oldRtpList[0]; 51 const inboundRtp = inboundRtpList[0]; 52 const fps = 1000.0 * (inboundRtp.framesReceived - oldRtp.framesReceived) / 53 (inboundRtp.timestamp - oldRtp.timestamp); 54 const result = { 55 bandwidth: bandwidth(oldStats, stats), 56 fps: fps, 57 width: inboundRtp.frameWidth, 58 height: inboundRtp.frameHeight 59 }; 60 oldStats = stats; 61 if (!result.bandwidth) { 62 return {}; 63 } 64 // Unbreak for debugging. 65 // con sole.log('Measure: ', performance.now(), " ", JSON.stringify(result)); 66 return result; 67 } 68 69 promise_test(async t => { 70 const pc1 = new RTCPeerConnection(); 71 t.add_cleanup(() => pc1.close()); 72 const stream = await getNoiseStream({video: true}); 73 t.add_cleanup(() => stream.getTracks().forEach(track => track.stop())); 74 const track = stream.getTracks()[0]; 75 const { sender } = pc1.addTransceiver(track); 76 77 let param = sender.getParameters(); 78 79 param.degradationPreference = 'maintain-framerate'; 80 await sender.setParameters(param); 81 82 const pc2 = new RTCPeerConnection(); 83 t.add_cleanup(() => pc2.close()); 84 85 exchangeIceCandidates(pc1, pc2); 86 await exchangeOfferAnswer(pc1, pc2); 87 await listenToConnected(pc1); 88 // Allow the keyframe to pass. 89 await new Promise(r => t.step_timeout(r, 1000)); 90 // Wait a few seconds to allow things to settle (rampup) 91 // We know that the generator is supposed to produce 640x480 92 // at 10 fps with a bandwidth exceeding 30 kbits/second. 93 await t.step_wait(async () => { 94 const measure = await measureStuff(pc2); 95 return (measure.bandwidth > minUnconstrainedBandwidth && 96 measure.width == 640 && 97 measure.fps > 9); 98 }, 'Test error: Preconditions not achieved', 30000, 500); 99 100 // Measure BW, resolution and frame rate over one second 101 // after measurements have stabilized. 102 await new Promise(r => t.step_timeout(r, 1000)); 103 const stats1 = await measureStuff(pc2); 104 105 // Constrain BW to 1/2 of measured value 106 const newBandwidth = stats1.bandwidth / 2; 107 // Guard against inappropriate bandwidth 108 assert_greater_than(newBandwidth, minUnconstrainedBandwidth/2, 109 "Test error: Constraint too low"); 110 111 const parameters = sender.getParameters(); 112 parameters.encodings[0].maxBitrate = newBandwidth; 113 await sender.setParameters(parameters); 114 // Wait until the expected result happens. 115 const kBandwidthMargin = 1.3; 116 // It takes time to adapt to a new bandwidth, time to scale down, 117 // and time to acknowledge that framerate should not be reduced. 118 // Measured time is around 16 seconds. 119 await t.step_wait(async () => { 120 let measure = await measureStuff(pc2); 121 return (measure.bandwidth && 122 measure.bandwidth < newBandwidth * kBandwidthMargin && 123 measure.width < stats1.width && 124 measure.fps > stats1.fps * 0.9); 125 }, 'Adaptation did not succeed', 126 30000, 500); 127 }, 'Maintain-framerate reduces resolution on bandwidth cut', { timeout: 35000 }); 128 129 </script>