129 lines
4.7 KiB
HTML
129 lines
4.7 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<meta name="timeout" content="long">
|
|
<title>RTCRtpSendParameters degradationPreference effect</title>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="../webrtc/RTCPeerConnection-helper.js"></script>
|
|
<script>
|
|
'use strict';
|
|
|
|
// This file contains tests that check that degradation preference
|
|
// actually has the desired effect. These tests take a long time to run.
|
|
|
|
// The signal generator will generate a video stream with at least this
|
|
// many bits per second if unconstrained.
|
|
const minUnconstrainedBandwidth = 30000;
|
|
|
|
// Returns incoming bandwidth usage between stats1 and stats2
|
|
// in bits per second.
|
|
function bandwidth(stats1, stats2) {
|
|
if (!stats1 || !stats2) {
|
|
return null;
|
|
}
|
|
const transport1 = [...stats1.values()].filter(({type}) => type === 'transport')[0];
|
|
const transport2 = [...stats2.values()].filter(({type}) => type === 'transport')[0];
|
|
const bytes = transport2.bytesReceived - transport1.bytesReceived;
|
|
// If time interval is too short for proper measurement, return null.
|
|
if (transport1.timestamp > transport2.timestamp - 100) {
|
|
return null;
|
|
}
|
|
// Multiply by 1000 to get per second, multiply by 8 to get bits.
|
|
const bandwidth = 1000 * 8 * bytes /
|
|
(transport2.timestamp - transport1.timestamp);
|
|
return bandwidth;
|
|
}
|
|
|
|
let oldStats;
|
|
|
|
// Returns tuple of { bandwidth, fps, x-res, y-res }
|
|
// Updates oldStats.
|
|
async function measureStuff(pc) {
|
|
const stats = await pc.getStats();
|
|
if (!oldStats) {
|
|
oldStats = stats;
|
|
return {};
|
|
}
|
|
// RTCInboundStreamStats
|
|
const oldRtpList = [...oldStats.values()].filter(({type}) => type === 'inbound-rtp');
|
|
const inboundRtpList = [...stats.values()].filter(({type}) => type === 'inbound-rtp');
|
|
const oldRtp = oldRtpList[0];
|
|
const inboundRtp = inboundRtpList[0];
|
|
const fps = 1000.0 * (inboundRtp.framesReceived - oldRtp.framesReceived) /
|
|
(inboundRtp.timestamp - oldRtp.timestamp);
|
|
const result = {
|
|
bandwidth: bandwidth(oldStats, stats),
|
|
fps: fps,
|
|
width: inboundRtp.frameWidth,
|
|
height: inboundRtp.frameHeight
|
|
};
|
|
oldStats = stats;
|
|
if (!result.bandwidth) {
|
|
return {};
|
|
}
|
|
// Unbreak for debugging.
|
|
// con sole.log('Measure: ', performance.now(), " ", JSON.stringify(result));
|
|
return result;
|
|
}
|
|
|
|
promise_test(async t => {
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const stream = await getNoiseStream({video: true});
|
|
t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
|
|
const track = stream.getTracks()[0];
|
|
const { sender } = pc1.addTransceiver(track);
|
|
|
|
let param = sender.getParameters();
|
|
|
|
param.degradationPreference = 'maintain-framerate';
|
|
await sender.setParameters(param);
|
|
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
exchangeIceCandidates(pc1, pc2);
|
|
await exchangeOfferAnswer(pc1, pc2);
|
|
await listenToConnected(pc1);
|
|
// Allow the keyframe to pass.
|
|
await new Promise(r => t.step_timeout(r, 1000));
|
|
// Wait a few seconds to allow things to settle (rampup)
|
|
// We know that the generator is supposed to produce 640x480
|
|
// at 10 fps with a bandwidth exceeding 30 kbits/second.
|
|
await t.step_wait(async () => {
|
|
const measure = await measureStuff(pc2);
|
|
return (measure.bandwidth > minUnconstrainedBandwidth &&
|
|
measure.width == 640 &&
|
|
measure.fps > 9);
|
|
}, 'Test error: Preconditions not achieved', 30000, 500);
|
|
|
|
// Measure BW, resolution and frame rate over one second
|
|
// after measurements have stabilized.
|
|
await new Promise(r => t.step_timeout(r, 1000));
|
|
const stats1 = await measureStuff(pc2);
|
|
|
|
// Constrain BW to 1/2 of measured value
|
|
const newBandwidth = stats1.bandwidth / 2;
|
|
// Guard against inappropriate bandwidth
|
|
assert_greater_than(newBandwidth, minUnconstrainedBandwidth/2,
|
|
"Test error: Constraint too low");
|
|
|
|
const parameters = sender.getParameters();
|
|
parameters.encodings[0].maxBitrate = newBandwidth;
|
|
await sender.setParameters(parameters);
|
|
// Wait until the expected result happens.
|
|
const kBandwidthMargin = 1.3;
|
|
// It takes time to adapt to a new bandwidth, time to scale down,
|
|
// and time to acknowledge that framerate should not be reduced.
|
|
// Measured time is around 16 seconds.
|
|
await t.step_wait(async () => {
|
|
let measure = await measureStuff(pc2);
|
|
return (measure.bandwidth &&
|
|
measure.bandwidth < newBandwidth * kBandwidthMargin &&
|
|
measure.width < stats1.width &&
|
|
measure.fps > stats1.fps * 0.9);
|
|
}, 'Adaptation did not succeed',
|
|
30000, 500);
|
|
}, 'Maintain-framerate reduces resolution on bandwidth cut', { timeout: 35000 });
|
|
|
|
</script>
|