110 lines
4.1 KiB
HTML
110 lines
4.1 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<title>RTCPeerConnection Simulcast Tests - setParameters/maxFramerate</title>
|
|
<meta name="timeout" content="long">
|
|
<script src="../third_party/sdp/sdp.js"></script>
|
|
<script src="simulcast.js"></script>
|
|
<script src="../RTCPeerConnection-helper.js"></script>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/resources/testdriver.js"></script>
|
|
<script src="/resources/testdriver-vendor.js"></script>
|
|
<script src="../../mediacapture-streams/permission-helper.js"></script>
|
|
<script>
|
|
async function queryReceiverStats(pc) {
|
|
const inboundStats = [];
|
|
await Promise.all(pc.getReceivers().map(async receiver => {
|
|
const receiverStats = await receiver.getStats();
|
|
receiverStats.forEach(stat => {
|
|
if (stat.type === 'inbound-rtp') {
|
|
inboundStats.push(stat);
|
|
}
|
|
});
|
|
}));
|
|
return inboundStats;
|
|
}
|
|
|
|
async function statsDelta(pc, t) {
|
|
const initialStats = await queryReceiverStats(pc);
|
|
await new Promise(resolve => t.step_timeout(resolve, 1000)); // Wait more.
|
|
const subsequentStats = await queryReceiverStats(pc);
|
|
return {initialStats, subsequentStats};
|
|
}
|
|
|
|
function calculateFramerate(newStats, oldStats) {
|
|
const deltaF = newStats.framesDecoded - oldStats.framesDecoded;
|
|
const deltaT = newStats.timestamp - oldStats.timestamp;
|
|
return deltaF / deltaT * 1000;
|
|
}
|
|
|
|
function calculateConservativeFramerate(newStats, oldStats) {
|
|
// The timestamp represents the exact point in time that the integer
|
|
// framesDecoded was sampled. For both samples, one time unit (say a
|
|
// nanosecond, i.e. virtually 0) could sway the integer framesDecoded value
|
|
// up to 1 frame. For checking that we don't exceed maxFramerate, in the worst
|
|
// case, the old timestamp is then at the end of a frame period (right before
|
|
// framesDecoded gets incremented) while the new timestamp is at the beginning
|
|
// of a frame period. Thus for avoiding intermittents we need to allow up to
|
|
// two frames more for the given sampling period, regardless of length.
|
|
const deltaF = newStats.framesDecoded - oldStats.framesDecoded - 2;
|
|
const deltaT = newStats.timestamp - oldStats.timestamp;
|
|
return deltaF / deltaT * 1000;
|
|
}
|
|
|
|
promise_test(async t => {
|
|
const expectedFramerates = [15, 10, 5];
|
|
const rids = [0, 1, 2];
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
await negotiateSimulcastAndWaitForVideo(
|
|
t,
|
|
await getCameraStream(t),
|
|
rids,
|
|
pc1,
|
|
pc2
|
|
);
|
|
|
|
// Wait for framerate to stabilize.
|
|
await new Promise(resolve => t.step_timeout(resolve, 1000));
|
|
|
|
// Assert that our framerate is bigger than 20, otherwise this test does not
|
|
// assert anything useful.
|
|
const defaultStats = await statsDelta(pc2, t);
|
|
defaultStats.subsequentStats.forEach((_, idx) => {
|
|
const actualFramerate = calculateFramerate(
|
|
defaultStats.subsequentStats[idx],
|
|
defaultStats.initialStats[idx]
|
|
);
|
|
assert_greater_than(actualFramerate, 20);
|
|
});
|
|
|
|
// Change the framerate on all layers.
|
|
const parameters = pc1.getSenders()[0].getParameters();
|
|
parameters.encodings.forEach((e, idx) => {
|
|
e.maxFramerate = expectedFramerates[idx];
|
|
});
|
|
await pc1.getSenders()[0].setParameters(parameters);
|
|
// Wait for the change to propagate to the receiver.
|
|
await new Promise(resolve => t.step_timeout(resolve, 100));
|
|
|
|
// Assert the approximate framerate
|
|
const newStats = await statsDelta(pc2, t);
|
|
|
|
const framerates = [];
|
|
newStats.subsequentStats.forEach((_, idx) => {
|
|
const expectedFramerate = expectedFramerates[idx];
|
|
const actualFramerate = calculateConservativeFramerate(
|
|
newStats.subsequentStats[idx],
|
|
newStats.initialStats[idx]
|
|
);
|
|
// Assert that the framerate is at most the expected framerate.
|
|
assert_less_than(actualFramerate, expectedFramerate);
|
|
framerates.push(actualFramerate);
|
|
});
|
|
// Assert that the framerates are ordered as configured.
|
|
assert_array_equals(framerates, framerates.toSorted((a, b) => a < b));
|
|
}, 'Simulcast setParameters maxFramerate reduces the framerate');
|
|
</script>
|