blob: a2da6cd139fa40978895bfc8ba2571384c280c8f [file] [log] [blame]
Harald Alvestrand1af7ffe2023-10-03 13:00:581<!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
Harald Alvestrand9df3aaa2023-10-04 19:32:1014// The signal generator will generate a video stream with at least this
15// many bits per second if unconstrained.
16const minUnconstrainedBandwidth = 30000;
17
Harald Alvestrand1af7ffe2023-10-03 13:00:5818// Returns incoming bandwidth usage between stats1 and stats2
19// in bits per second.
20function bandwidth(stats1, stats2) {
Harald Alvestrand9df3aaa2023-10-04 19:32:1021 if (!stats1 || !stats2) {
22 return null;
23 }
Harald Alvestrand1af7ffe2023-10-03 13:00:5824 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;
Harald Alvestrand9df3aaa2023-10-04 19:32:1027 // 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.
Harald Alvestrand1af7ffe2023-10-03 13:00:5832 const bandwidth = 1000 * 8 * bytes /
33 (transport2.timestamp - transport1.timestamp);
34 return bandwidth;
35}
36
Harald Alvestrand9df3aaa2023-10-04 19:32:1037let oldStats;
38
Harald Alvestrand1af7ffe2023-10-03 13:00:5839// Returns tuple of { bandwidth, fps, x-res, y-res }
Harald Alvestrand9df3aaa2023-10-04 19:32:1040// Updates oldStats.
41async function measureStuff(pc) {
42 const stats = await pc.getStats();
43 if (!oldStats) {
44 oldStats = stats;
45 return {};
46 }
Harald Alvestrand1af7ffe2023-10-03 13:00:5847 // RTCInboundStreamStats
Harald Alvestrand9df3aaa2023-10-04 19:32:1048 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);
Harald Alvestrand1af7ffe2023-10-03 13:00:5854 const result = {
Harald Alvestrand9df3aaa2023-10-04 19:32:1055 bandwidth: bandwidth(oldStats, stats),
Harald Alvestrand1af7ffe2023-10-03 13:00:5856 fps: fps,
Harald Alvestrand9df3aaa2023-10-04 19:32:1057 width: inboundRtp.frameWidth,
58 height: inboundRtp.frameHeight
Harald Alvestrand1af7ffe2023-10-03 13:00:5859 };
Harald Alvestrand9df3aaa2023-10-04 19:32:1060 oldStats = stats;
61 if (!result.bandwidth) {
62 return {};
63 }
Harald Alvestrand1af7ffe2023-10-03 13:00:5864 // Unbreak for debugging.
65 // con sole.log('Measure: ', performance.now(), " ", JSON.stringify(result));
66 return result;
67}
68
Harald Alvestrand1af7ffe2023-10-03 13:00:5869promise_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
Harald Alvestrand1af7ffe2023-10-03 13:00:5879 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);
Harald Alvestrand9df3aaa2023-10-04 19:32:1088 // Allow the keyframe to pass.
89 await new Promise(r => t.step_timeout(r, 1000));
Harald Alvestrand1af7ffe2023-10-03 13:00:5890 // 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.
Harald Alvestrand9df3aaa2023-10-04 19:32:1093 await t.step_wait(async () => {
94 const measure = await measureStuff(pc2);
95 return (measure.bandwidth > minUnconstrainedBandwidth &&
Harald Alvestrand1af7ffe2023-10-03 13:00:5896 measure.width == 640 &&
97 measure.fps > 9);
Harald Alvestrand9df3aaa2023-10-04 19:32:1098 }, 'Test error: Preconditions not achieved', 30000, 500);
Harald Alvestrand1af7ffe2023-10-03 13:00:5899
100 // Measure BW, resolution and frame rate over one second
Harald Alvestrand9df3aaa2023-10-04 19:32:10101 // after measurements have stabilized.
102 await new Promise(r => t.step_timeout(r, 1000));
103 const stats1 = await measureStuff(pc2);
Harald Alvestrand1af7ffe2023-10-03 13:00:58104
105 // Constrain BW to 1/2 of measured value
106 const newBandwidth = stats1.bandwidth / 2;
Harald Alvestrand9df3aaa2023-10-04 19:32:10107 // Guard against inappropriate bandwidth
108 assert_greater_than(newBandwidth, minUnconstrainedBandwidth/2,
109 "Test error: Constraint too low");
Harald Alvestrand1af7ffe2023-10-03 13:00:58110
111 const parameters = sender.getParameters();
112 parameters.encodings[0].maxBitrate = newBandwidth;
113 await sender.setParameters(parameters);
114 // Wait until the expected result happens.
Harald Alvestrand1af7ffe2023-10-03 13:00:58115 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.
Harald Alvestrand9df3aaa2023-10-04 19:32:10119 await t.step_wait(async () => {
120 let measure = await measureStuff(pc2);
121 return (measure.bandwidth &&
122 measure.bandwidth < newBandwidth * kBandwidthMargin &&
Harald Alvestrand1af7ffe2023-10-03 13:00:58123 measure.width < stats1.width &&
124 measure.fps > stats1.fps * 0.9);
Harald Alvestrand9df3aaa2023-10-04 19:32:10125 }, 'Adaptation did not succeed',
126 30000, 500);
Harald Alvestrand1af7ffe2023-10-03 13:00:58127}, 'Maintain-framerate reduces resolution on bandwidth cut', { timeout: 35000 });
128
129</script>