Skip to content

Commit

Permalink
Rewrite "maintain-framerate" in terms of t.step_wait
Browse files Browse the repository at this point in the history
This makes the test easier to read.

Bug: none
Change-Id: I01f6a2b638a3fa3d0aacb4ee5653e41ea9d11394
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4907738
Reviewed-by: Guido Urdaneta <[email protected]>
Commit-Queue: Harald Alvestrand <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1205386}
  • Loading branch information
alvestrand authored and chromium-wpt-export-bot committed Oct 4, 2023
1 parent a4288b9 commit 9df3aaa
Showing 1 changed file with 52 additions and 43 deletions.
95 changes: 52 additions & 43 deletions mst-content-hint/RTCRtpSendParameters-degradationEffect.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,56 +11,61 @@
// 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;
// Multiply by 1000 to get per second, divide by 8 to get bits.
// 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 }
async function measureStuff(t, pc, intervalMs) {
const stats1 = await pc.getStats();
await new Promise(r => t.step_timeout(r, intervalMs));
const stats2 = await pc.getStats();
// Updates oldStats.
async function measureStuff(pc) {
const stats = await pc.getStats();
if (!oldStats) {
oldStats = stats;
return {};
}
// RTCInboundStreamStats
const inboundRtp1List = [...stats1.values()].filter(({type}) => type === 'inbound-rtp');
const inboundRtp2List = [...stats2.values()].filter(({type}) => type === 'inbound-rtp');
const inboundRtp1 = inboundRtp1List[0];
const inboundRtp2 = inboundRtp2List[0];
const fps = 1000 * (inboundRtp2.framesReceived - inboundRtp1.framesReceived) /
(inboundRtp2.timestamp - inboundRtp1.timestamp);
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(stats1, stats2),
bandwidth: bandwidth(oldStats, stats),
fps: fps,
width: inboundRtp2.frameWidth,
height: inboundRtp2.frameHeight
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;
}

// Wait for a certain condition to be true on the traffic measures
// on the PC. Will typically be conditions on resolution, framerate
// or bandwidth.
async function waitForCondition(t, pc, condition, maxWait, stepName) {
let counter = 1;
let measure = await measureStuff(t, pc, 1000);
while (counter < maxWait && !condition(measure)) {
measure = await measureStuff(t, pc, 1000);
counter += 1;
}
assert_true(condition(measure),
`failure in ${stepName}, measure is ${JSON.stringify(measure)}`);
return condition(measure);
}

promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
Expand All @@ -71,9 +76,6 @@

let param = sender.getParameters();

assert_equals(param.degradationPreference, undefined,
'Expect initial param.degradationPreference to be undefined');

param.degradationPreference = 'maintain-framerate';
await sender.setParameters(param);

Expand All @@ -83,38 +85,45 @@
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.
assert_true(await waitForCondition(t, pc2, (measure) => {
return (measure.bandwidth > 30000 &&
await t.step_wait(async () => {
const measure = await measureStuff(pc2);
return (measure.bandwidth > minUnconstrainedBandwidth &&
measure.width == 640 &&
measure.fps > 9);
}, 60, 'preconditions'));
}, 'Test error: Preconditions not achieved', 30000, 500);

// Measure BW, resolution and frame rate over one second
const stats1 = await measureStuff(t, pc2, 1000);
// 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.
let stats2 = await measureStuff(t, pc2, 1000);
let counter = 1;
const maxWaitCount = 20;
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.
assert_true(await waitForCondition(t, pc2, (measure) => {
return (measure.bandwidth < newBandwidth * kBandwidthMargin &&
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);
}, 60, 'adaptation'),
`Target bandwidth ${newBandwidth * kBandwidthMargin}, target min FPS ${stats1.fps * 0.9}`);
}, 'Adaptation did not succeed',
30000, 500);
}, 'Maintain-framerate reduces resolution on bandwidth cut', { timeout: 35000 });

</script>

0 comments on commit 9df3aaa

Please sign in to comment.