tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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>